Regex 正则表达式工作,但收到警告:在正则表达式错误中多次匹配空字符串
我有一个字符串,其中有许多组件需要提取。这些都是结构良好且可预测的,但它们出现的顺序各不相同。下面是一个片段,它演示了字符串可能是什么样子,以及我用来提取所需信息的正则表达式。这段代码运行正常,我得到了预期的输出Regex 正则表达式工作,但收到警告:在正则表达式错误中多次匹配空字符串,regex,perl,regex-lookarounds,Regex,Perl,Regex Lookarounds,我有一个字符串,其中有许多组件需要提取。这些都是结构良好且可预测的,但它们出现的顺序各不相同。下面是一个片段,它演示了字符串可能是什么样子,以及我用来提取所需信息的正则表达式。这段代码运行正常,我得到了预期的输出 my $str1 = '(test1=cat)(test2=dog)(test3=mouse)'; # prints cat\ndog\mouse $str1 = '(test1=cat)(test3=mouse)(test2=dog)(test1=cat)'; # p
my $str1 = '(test1=cat)(test2=dog)(test3=mouse)'; # prints cat\ndog\mouse
$str1 = '(test1=cat)(test3=mouse)(test2=dog)(test1=cat)'; # prints cat\ndog\nmouse
$str1 = '(test3=mouse)(test1=cat)'; # prints cat\nempty\nmouse
$str1 = '(test3=mouse)(test2=dog)'; # prints empty\ndog\nmouse
my $pattern1 = '(?=.*\(test1=(.*?)\))*(?=.*\(test2=(.*?)\))*(?=.*\(test3=(.*?)\))*';
if (my @map = $str1 =~ /$pattern1/) {
foreach my $match (@map) {
say $match if $match;
say "empty" if !$match;
}
}
上述最后一个字符串的预期和接收结果如下:
empty
dog
mouse
但是,除了预期的响应之外,还有以下警告:
(?=.*\(test1=(.*?)\))* matches null string many times in regex; marked by <-- HERE in m/(?=.*\(test1=(.*?)\))* <-- HERE (?=.*\(test2=(.*?)\))*(?=.*\(test3=(.*?)\))*/ at /path/to/scratch1.pl line 32.
(?=.*\(test2=(.*?)\))* matches null string many times in regex; marked by <-- HERE in m/(?=.*\(test1=(.*?)\))*(?=.*\(test2=(.*?)\))* <-- HERE (?=.*\(test3=(.*?)\))*/ at /path/to/scratch1.pl line 32.
(?=.*\(test3=(.*?)\))* matches null string many times in regex; marked by <-- HERE in m/(?=.*\(test1=(.*?)\))*(?=.*\(test2=(.*?)\))*(?=.*\(test3=(.*?)\))* <-- HERE / at /path/to/scratch1.pl line 32.
(?=.*\(test1=(.*?\)*在正则表达式中多次匹配空字符串;通过多次匹配前瞻(?=…)
来标记是没有意义的。它不使用对象字符串中的任何数据,因此如果匹配一次,它将无限期地匹配
您需要进行的主要更改是将(?=.*\(test1=(.*))*
等替换为(?=.*\(test1=(.*))?
。这只会使你的前瞻性成为“可选的”,并将消除你的警告
使用严格;
使用“全部”警告;
使用数据::转储;
我的$pattern=qr/
(?=.*\(test1=(.*))?
(?=.*\(test2=(.*))?
(?=.*\(test3=(.*))?
/x;
我的@strings=qw/
(test1=cat)(test2=dog)(test3=mouse)
(test1=cat)(test3=mouse)(test2=dog)(test1=cat)
(test3=鼠标)(test1=猫)
(test3=老鼠)(test2=狗)
/;
对于我的$str(@strings){
下一步,除非我的@map=$str=~/$pattern/;
$\uz/=@map的“空”;
dd\@地图;
}
输出
[“猫”、“狗”、“鼠标”]
[“猫”、“狗”、“老鼠”]
[“猫”、“空”、“鼠标”]
[“空”、“狗”、“鼠标”]
然而,这听起来像是另一个让单个正则表达式模式做太多工作的例子。您是用Perl编写的,为什么不使用它呢
以下代码假定与上面的完整程序具有相同的头,包括@strings
的定义。我只更改了for
循环的
用于我的$str(@strings){
my@map=map{$str=~/\(test$\=([^()]*)\)/x?$1:'empty'}1..3;
dd\@地图;
}
输出
[“猫”、“狗”、“鼠标”]
[“猫”、“狗”、“老鼠”]
[“猫”、“空”、“鼠标”]
[“空”、“狗”、“鼠标”]
或者可能是一些不同的东西是合适的。哈希对于这类事情很有用
用于我的$str(@strings){
我的%map=$str=~/\((test\d+)=([^()]*)\)/gx;
dd\%map;
}
输出
{test1=>“猫”,test2=>“狗”,test3=>“鼠标”}
{test1=>“猫”,test2=>“狗”,test3=>“老鼠”}
{test1=>“猫”,test3=>“鼠标”}
{test2=>“狗”,test3=>“老鼠”}
之所以发出警告,是因为(?=…)*
对这一伟大的解释毫无意义。当然要用吗?而不是*做了这个把戏。我喜欢你在没有前瞻性正则表达式的情况下实现它的方式。我会考虑合并它。看起来对我正在做的其他事情也很有用。再次感谢@不客气。经常会遇到这样的问题:作者试图将所有内容都塞进一个正则表达式模式中。这很可能是不必要的,而且对于复杂的条件来说几乎从来都不明智。Perl为您提供了逻辑运算符,因此您可以说if(/aaa/或/bbb/)…
,而不是if(/aaa | bbb/)…
,它可以真正改变代码的可读性