合并两个几乎相似的文本

时间:2011-11-09 08:49:57

标签: xml perl diff string-comparison

我遇到了以下棘手的问题:

我有两个基本相同的文本,其中一个是xml-tagged,另一个不是。

包含xml-tags的文本中的拼写已经规范化 - 这是我不想要的。这就是为什么我在寻找合并两个文本的方法:我必须用非常相似但不完全相同的纯文本替换xml文本,保留xml结构。

有人知道这是否可行?有没有办法解决Perl中的问题?

非常感谢!

亚历


示例

规范化的XML:

<div2>
<head>Title</head>
<p>Here is some normalized sample text.</p>
<p>The orthograph has been changed.</p>
</div2>

来自原始明文:

  

性标题

     

这是一些标准化的样本文本。

     

ortographe已被更改。

我希望得到这样的输出:

<div2>
<head>Title</head>
<p>Here is some normalised sample texte.</p>
<p>The ortographe has been changed.</p>
</div2>

2 个答案:

答案 0 :(得分:1)

嗯......我建议使用Algorithm::Diff。基本上,如果你采用两个文本的逐字符差异,你应该得到这样的东西:

[+<div2>+]
[+<head>+]Tit[-e-]l[+e</head>+]
[+<p>+]Here is some normali[-s-][+z+]ed sample text[-e-].[+</p>+]
[+<p>+]The ort[+h+]ograph[-e-] has been changed.[+</p>+]
[+</div2>+]

您会注意到有一些XML标记插入穿插了文本更改。现在,如果你只是从+版本和-版本的文本中获取了标记,那么你应该得到你想要的组合文本。

为了达到最佳效果,我建议使用智能标记器将XML标记视为单个标记,以便例如<p>foo</p>将分为<p>foo</p>。这不仅使得差异更快,并且更容易解析输出,而且还避免了diff算法可能将标记分成几个块或将其与文本混淆的风险。

以下是一些示例代码:

sub merge_tags {
    my ($orig, $tagged) = @_;

    # tokenize strings into tags and chars (could use a real XML parser here)
    $_ = [/\G(<(?:[^>"']|"[^"]*"|'[^']*')*>|.)/sg] for $orig, $tagged;

    require Algorithm::Diff;
    my $diff = Algorithm::Diff->new( $orig, $tagged );

    my @output;
    while ($diff->Next) {
        if ($diff->Diff) {
            my @text = grep !/^<.*>$/s, $diff->Items(1);
            my @tags = grep  /^<.*>$/s, $diff->Items(2);
            # kluge: output opening tags first
            push @output, shift @tags while @tags and $tags[0] !~ /^<\//;
            push @output, @text, @tags;
        }
        else {
            push @output, $diff->Same;
        }
    }
    return join "", @output;
}

我确信这段代码可以改进(例如,它可以更聪明地标记嵌套),但至少它适用于您的样本输入。

答案 1 :(得分:0)

如果总是有相同数量的单词和相同的顺序 - 您可以逐个替换单词。