Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/regex/17.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Regex Perl正则表达式/嵌套短语替换_Regex_Perl - Fatal编程技术网

Regex Perl正则表达式/嵌套短语替换

Regex Perl正则表达式/嵌套短语替换,regex,perl,Regex,Perl,我有一个perl脚本,它逐行处理文本文件,并将这些行中的短语转换为链接(特别是在mediawiki标记中,但我怀疑任何标记都会有相同的问题)。当一个短语是另一个短语的子集时,我会陷入困境。在这些情况下,会创建太多链接 例如,如果“总务委员会”和“年度总务委员会会议”是其中两个短语: 总务委员会会议应每月召开一次 已正确转换为: [[总理事会]会议应每月举行一次 但是, 年度总务委员会会议应在5月举行 错误地转换为: [#AGCM |年度[#GC |总务委员会]]会议应于5月举行 也就是说,我的脚

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

例如,如果“总务委员会”和“年度总务委员会会议”是其中两个短语:

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

已正确转换为:

[[总理事会]会议应每月举行一次

但是,

年度总务委员会会议应在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;
    }
}
当一个短语与另一个短语可以找到时,有没有关于如何避免匹配/替换的建议


更新:根据一些问题进行澄清:每个短语独立;没有一个优先于另一个。用最长的代替最短的就足以得到我所需要的。

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

这个节目展示了这个想法。键按长度递减进行排序,以便首先找到最长的匹配,然后用
交替字符作为分隔符连接

然后,只需找到构建模式的所有匹配项并将其替换为相应的哈希元素值。这可以在单个替换中完成,而不需要循环

注意,您可能需要考虑使用<<代码> map >代码>使用“代码> > s+<代码>代替空白,并在字符串前后放置<代码> \b>代码,以确保字符串匹配不是较长单词的一部分。另外,

/i
regex修饰符可能与允许独立于大小写的匹配相关

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";

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

这个节目展示了这个想法。键按长度递减进行排序,以便首先找到最长的匹配,然后用
交替字符作为分隔符连接

然后,只需找到构建模式的所有匹配项并将其替换为相应的哈希元素值。这可以在单个替换中完成,而不需要循环

注意,您可能需要考虑使用<<代码> map >代码>使用“代码> > s+<代码>代替空白,并在字符串前后放置<代码> \b>代码,以确保字符串匹配不是较长单词的一部分。另外,

/i
regex修饰符可能与允许独立于大小写的匹配相关

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";

如何在不重新启动pos()=0的情况下获得嵌套替换?没关系。这很容易排除以前的链接。我想真正的问题是先来的是鸡还是蛋?如何在不重新启动pos()=0的情况下获得嵌套替换?没关系。这很容易排除以前的链接。我想真正的问题是先来的是鸡还是先来的蛋?还是先来,先上。这还不足以说它已经“见过”了。那又怎样,谁在乎呢。这只是基于第一次看到的列表的优先级。没有逻辑,它只是一个基于什么是第一的简单列表。这不是很程序化,但这就是问题所在,不是吗?@sln:恐怕我无法理解你的评论,只能假设你误解了程序的工作原理。答案很好。使用“或”(通过“|”)的力量让我找到了我需要去的地方。它仍然是先来先发球。这还不足以说它已经“被看见”。那又怎样,谁在乎呢。这只是基于第一次看到的列表的优先级。没有逻辑,它只是一个基于什么是第一的简单列表。这不是很程序化,但这就是问题所在,不是吗?@sln:恐怕我无法理解你的评论,只能假设你误解了程序的工作原理。答案很好。使用“或”(通过“|”)的力量让我找到了我需要去的地方。