1

我有一个要在字符串中查找的模式列表。这些模式很多,并且包含许多我只想按字面匹配的元字符。所以这是元引用的完美应用\Q..\E。复杂之处在于我需要将模式的变量列表加入到正则表达式中。

use strict;
use warnings;
# sample string to represent my problem
    my $string = "{{a|!}} Abra\n{{b|!!}} {{b}} Hocus {{s|?}} Kedabra\n{{b|+?}} {{b|??}} Pocus\n {{s|?}}Alakazam\n";

# sample patterns to look for    
my @patterns = qw({{a|!}} {{s|?}} {{s|+?}} {{b|?}});
# since these patterns can be anything, I join the resulting array into a variable-length regex
my $regex = join("|",@patterns);

my @matched = $string =~ /$regex(\s\w+\s)/; # Error in matching regex due to unquoted metacharacters
print join("", @matched); # intended result: Hocus\n Pocus\n

当我尝试将元引用引入连接操作时,它们似乎没有效果。

# quote all patterns so that they match literally, but make sure the alternating metacharacter works as intended
my $qmregex = "\Q".join("\E|\Q", @patterns)."\E";

my @matched = $string =~ /$qmregex(\s\w+\s)/; # The same error

由于某种原因,当元引用包含在我用作正则表达式的字符串中时,它不起作用。对我来说,它们只有在直接添加到正则表达式时才起作用,/\Q$anexpression\E/但据我所知,这对我来说不是一个选择。我该如何解决这个问题?

4

1 回答 1

1

我不明白您的预期结果,因为Abra并且Kedabra是唯一以任何模式开头的字符串。

要解决您的问题,您必须将正则表达式的每个组件分别转义为\Q\E仅影响它们出现的字符串的值,因此"\Q"and"\E"只是空字符串"",并且"\E|\Q"只是"|". 你可以写

my $qmregex = join '|', map "\Q$_\E", @patterns;

但调用quotemeta函数更简单。

您还必须将列表括在括号中(?:...)以隔离交替,并将/g修饰符应用于正则表达式匹配以查找字符串中的所有出现。

尝试

use strict;
use warnings;

my $string = "{{a|!}} Abra\n{{b|!!}} {{b}} Hocus {{s|?}} Kedabra\n{{b|+?}} {{b|??}} Pocus\n {{s|?}}Alakazam\n";

my @patterns = qw(  {{a|!}} {{s|?}} {{s|+?}} {{b|?}}  );

my $regex = join '|', map quotemeta, @patterns;
my @matched = $string =~ /(?:$regex)(\s\w+\s)/g;
print @matched;

输出

 Abra
 Kedabra
于 2012-04-08T22:33:55.607 回答