我遇到了一个奇怪的正则表达式问题.... 我有一个文件,我正在做一个替换...作为一个例子我想要替换 带有“DEXX / AREX”的“DEXX” 然后用下一个替换替换...... “AREX”与“AREX / CUBE”
DEXX和AREX存储在哈希中,如此.... “DEXX”=> “AREX” “AREX”=> “CUBE”
我的正则表达式就是这个......
foreach (keys %hashstore){
$doc=~s!\b($_)\b!$1/$hashstore{$_}!ig;
}
正在发生的事情是“DEXX”被替换为“DEXX / AREX”,但是当遇到“DEXX / AREX”时,正则表达式正在将“DEXX / AREX”替换为“DEXX / AREX / CUBE”当它发现它是一个独立的单词而不是像“DEXX / AREX”这样的另一个组合的一部分时,要替换“AREX”
似乎将“/”视为单词边界。 有没有人遇到这个或知道它周围的解决方案? 非常感谢! 艾米
答案 0 :(得分:5)
但是/
是一个单词边界。来自perldoc perlreref:
\b
匹配字边界(\w
和\W
之间)。
根据您在下面的评论,您应该避免循环:
#!/usr/bin/perl
use strict; use warnings;
use Regex::PreSuf;
my %lookup = (
"DEXX" => "AREX",
"AREX" => "CUBE",
);
my $doc = 'DEXX AREX AREX DEXX AREX DEXX DEXX DEXX AREX';
my $re = presuf keys %lookup;
$doc =~ s{($re)}{$1/$lookup{$1}}g;
print $doc, "\n";
输出:
DEXX/AREX AREX/CUBE AREX/CUBE DEXX/AREX AREX/CUBE DEXX/AREX DEXX/AREX DEXX/AREX AREX/CUBE
当然,如果您只有两个键,则不必使用Regex::PreSuf:
s{(AREX|DEXX)}{$1/$lookup{$1}}g;
也会这样做。但是,对于更长的密钥列表,我发现Regex::PreSuf非常方便。
更新:当然,如果文本中的任何情况都可以出现密钥,则可以在查找替换时使用uc
进行转换:
所以,
$doc =~ s{($re)}{join '/', uc($1), $lookup{uc $1}}eig;
或
$doc =~ s{($re)}{join '/', $1, $lookup{uc $1}}eig;
取决于您的需求。
此外, ysth 在评论中指出“在5.10及更高版本中,Regex :: PreSuf在大多数情况下生成的轮廓正则比天真轮换更差。”所以,
my $re = join '|', map quotemeta, sort { length($b) <=> length($a) } keys %lookup;
可能会更好。如果某些键可能是其他键的初始子串,则需要sort
。
答案 1 :(得分:2)
单词边界是\w
和\W
之间的任何时间的转换,如果您正在处理ASCII,则可以说是[a-zA-Z0-9_]
和[^a-zA-Z0-9_]
。
你应该能够通过使用负面的lookbehind来解决这个问题:
foreach (keys %hashstore){
$doc=~s!(?<!/)\b($_)\b!$1/$hashstore{$_}!ig;
}
答案 2 :(得分:2)
\ b相当于(虽然比(?:(?<!\w)(?=\w)|(?<=\w)(?!\w))
效率更高)。如果你想要一组不同于默认字符的单词字符,只需使用它,但用适当的字符类替换\ w。
答案 3 :(得分:1)
首先,我感谢思南(他不是关于Perl的问题吗?我知道我已经潜伏了很长时间......)和ysth。多亏了这两个,我对正则表达式有了更好的把握。我的解决方案是以下......
my $pat = join '|', keys(%hashstore);
$doc =~ s!\b($pat)\b!$1/$hashstore{uc($1)}!ig;
我遇到的问题是我更换了替换件!通常情况下,我真的试着把这些事情搞清楚,但这是一个如此紧迫的截止日期和思南和你们,你们两个都严厉摇滚! 艾米
答案 4 :(得分:0)
从\b
的角度来看,界限往往不是你想要的,特别是考虑到英语单词可以包含撇号和破折号,并且当你放置\b
时这些行为与字母的行为非常不同在他们旁边。有关此问题的更多说明,请参阅this answer,和如何应对此问题。