2

我有一个 perl 脚本,它逐行处理文本文件并将这些行中的短语转换为链接(特别是在 mediawiki 标记中,但我怀疑任何标记都会有同样的问题)。当一个短语是另一个短语的子集时,我会陷入困境。在这些情况下,会创建太多链接。

例如,如果“General Committee”和“Annual General Committee Meeting”是短语中的两个:

总务委员会会议每月召开一次。

正确转换为:

[[#GC|总务委员会]] 会议每月召开一次。

然而,

年度总务委员会会议将于 5 月举行。

被错误地转换为:

[[#AGCM|年度[[#GC|总务委员会]]会议]]将于5月举行。

也就是说,我的脚本是在“年度总务委员会会议”中找到短语“总务委员会”,并在我不想要的地方插入一个链接。在这个例子中应该只有一个到 AGCM 的链接。

相关的perl代码是:

my($line) = $_;
foreach $phrase (keys(%phrases))  # the phrases to replace mapped to their links
{
    my($link) = $phrases{$phrase};
    if ($line =~ m/$phrase/)
    {
        $line =~ s/$phrase/[[#$link|$phrase]]/g;
    }
}

当可以找到一个短语与另一个短语时如何避免匹配/替换的任何建议?

更新:基于一些问题的澄清:每个短语都是独立的;没有一个优先于另一个。以最长的时间超过最短的时间就足以得到我需要的东西。

4

1 回答 1

4

您应该构建一个与一次比较中的任何哈希键匹配的正则表达式。

这个程序显示了这个想法。键按长度递减排序,以便首先找到最长的匹配项,然后与|替换字符连接作为分隔符。

然后只需找到所有出现的已构建模式并将其替换为相应的哈希元素值即可。这可以在一次替换中完成,而不需要循环。

请注意,您可能需要考虑插入 amap\s+代替空格,并可能\b在字符串之前和之后放置以确保匹配的字符串不是较长单词的一部分。此外,/i正则表达式修饰符可能与允许与大小写无关的匹配有关。

use strict;
use warnings;

my %phrases = (
  'General Committee' => '[[#GC|General Committee]]',
  'Annual General Committee Meeting' => '[[#AGCM|Annual General Committee Meeting]]',
);

my $text = <<END;
The General Committee meeting shall meet once a month.
The Annual General Committee Meeting shall be held in May.
END

my $regex = join '|', sort { length $b <=> length $a } keys %phrases;

$text =~ s/($regex)/$phrases{$1}/g;

print $text, "\n";

输出

The [[#GC|General Committee]] meeting shall meet once a month.
The [[#AGCM|Annual General Committee Meeting]] shall be held in May.
于 2012-08-13T00:44:05.147 回答