Regex有效,但收到警告:在Regex错误中多次匹配空字符串



我有一个字符串,其中包含许多需要提取的组件。这些都是很好的形式和可预测的,但它们出现的顺序各不相同。下面是一个片段,它说明了字符串的外观以及我用来提取所需信息的正则表达式。这段代码有效,我得到了预期的输出。

my $str1 = '(test1=cat)(test2=dog)(test3=mouse)';         # prints catndogmouse
$str1 = '(test1=cat)(test3=mouse)(test2=dog)(test1=cat)'; # prints catndognmouse
$str1 = '(test3=mouse)(test1=cat)';                       # prints catnemptynmouse
$str1 = '(test3=mouse)(test2=dog)';                       # prints emptyndognmouse
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.

这告诉我,虽然我的regex工作,但它可能有一些问题。

我如何调整上面的正则表达式以在消除警告的同时继续按预期工作?

以下是我必须处理的一些限制:

  • 必须保持结果的顺序(例如,"test1"将始终是数组的第一个元素)
  • 字段名并不是真正的"testN",我必须使用许多唯一的字段名,这些都是静态值
  • 重复是可以的,但应该使用最后一个(上面的脚本可以做到这一点)

我通常不使用查找,所以我的错误可能是初步的(希望如此)。非常感谢您的任何建议或反馈。谢谢

编辑-运行Perl 5.20

多次匹配前瞻(?=...)是没有意义的。它不消耗对象字符串中的任何数据,因此如果匹配一次,它将无限期地匹配

您需要做的主要更改是将(?=.*(test1=(.*?)))*等替换为(?=.*(test1=(.*?)))?。这只是让你的前瞻性"可选",并将消除你的警告

use strict;
use warnings 'all';
use Data::Dump;
my $pattern = qr/
(?= .* ( test1= (.*?) ) )?
(?= .* ( test2= (.*?) ) )?
(?= .* ( test3= (.*?) ) )?
/x;
my @strings = qw/
(test1=cat)(test2=dog)(test3=mouse)
(test1=cat)(test3=mouse)(test2=dog)(test1=cat)
(test3=mouse)(test1=cat)
(test3=mouse)(test2=dog)
/;
for my $str ( @strings ) {
next unless my @map = $str =~ /$pattern/;
$_ //= 'empty' for @map;
dd @map;
}

输出

["cat", "dog", "mouse"]
["cat", "dog", "mouse"]
["cat", "empty", "mouse"]
["empty", "dog", "mouse"]

然而,这听起来像是让一个正则表达式模式做太多工作的另一种情况。您正在用Perl编写,为什么不使用它呢?

以下代码假设与上面的完整程序具有相同的头,直到并包括@strings的定义。for循环是我所改变的全部

for my $str ( @strings ) {
my @map = map {  $str =~ / ( test$_= ( [^()]* ) )/x ? $1 : 'empty' } 1 .. 3;
dd @map;
}

输出

["cat", "dog", "mouse"]
["cat", "dog", "mouse"]
["cat", "empty", "mouse"]
["empty", "dog", "mouse"]

或者可能是一些不同的东西是合适的。哈希对这类事情很有用

for my $str ( @strings ) {
my %map = $str =~ / ( ( testd+ ) = ( [^()]* ) ) /gx; 
dd %map;
}

输出

{ test1 => "cat", test2 => "dog", test3 => "mouse" }
{ test1 => "cat", test2 => "dog", test3 => "mouse" }
{ test1 => "cat", test3 => "mouse" }
{ test2 => "dog", test3 => "mouse" }

最新更新