我的搜索文本如下。
...
...
var strings = ["aaa","bbb","ccc","ddd","eee"];
...
...
它包含许多行(实际上是一个javascript文件),但需要解析变量字符串中的值,即aaa、bbb、ccc、ddd、eee
下面是Perl代码,或者在底部使用PHP
my $str = <<STR;
...
...
var strings = ["aaa","bbb","ccc","ddd","eee"];
...
...
STR
my @matches = $str =~ /(?:\"(.+?)\",?)/g;
print "@matches";
我知道上面的脚本会匹配所有瞬间,但它也会解析其他行中的字符串(“xyz”)。所以我需要检查字符串var字符串=
/var strings = \[(?:\"(.+?)\",?)/g
使用上面的正则表达式,它将解析aaa。
/var strings = \[(?:\"(.+?)\",?)(?:\"(.+?)\",?)/g
使用上面,将获得aaa和bbb。所以为了避免正则表达式重复,我使用了''量词,如下所示。
/var strings = \[(?:\"(.+?)\",?)+/g
但是我只有eee,所以我的问题是为什么我只有在使用量词时才得到eee?
更新1:使用PHPpreg_match_all(这样做是为了获得更多关注:-))
$str = <<<STR
...
...
var strings = ["aaa","bbb","ccc","ddd","eee"];
...
...
STR;
preg_match_all("/var strings = \[(?:\"(.+?)\",?)+/",$str,$matches);
print_r($matches);
更新2:为什么它匹配eee?因为(?:\"(. ?) \",?)
的贪婪。通过删除greedity/var字符串 = \[(?:\"(. ?) \",?) ? /
aaa将被匹配。但是为什么只有一个结果?有什么方法可以通过使用单个正则表达式来实现吗?
这是一个单正则表达式解决方案:
/(?:\bvar\s+strings\s*=\s*\[|\G,)\s*"([^"]*)"/g
\G
是一个零宽度断言,它匹配上一个匹配结束的位置(如果是第一次匹配尝试,则匹配字符串的开头)。所以这就像:
var\s+strings\s*=\s*[\s*"([^"]*)"
…第一次尝试,然后:
,\s*"([^"]*)"
…在那之后,但是每场比赛都必须从最后一场比赛结束的地方开始。
这是一个PHP的演示,但它也可以在Perl中运行。
您可能更喜欢这个解决方案,它首先使用/g
修饰符查找字符串var字符串=[
。这将\G
设置为在[
之后立即匹配下一个正则表达式,该正则表达式查找所有紧跟在后面的双引号字符串,可能前面有逗号或空格。
my @matches;
if ($str =~ /var \s+ strings \s* = \s* \[ /gx) {
@matches = $str =~ /\G [,\s]* "([^"]+)" /gx;
}
尽管使用了/g
修饰符,您的regex/var字符串 = \[(?:\"(. ?) \",?) /g
只匹配一次,因为没有第二次出现var字符串=[
。每次匹配都返回一个捕获变量的值列表1美元
,2美元
,3美元
等。当匹配完成时,/(?:"(. ?)",?) /
(不需要转义双引号)将多个值捕获到1美元
中,只留下最终值。您需要编写类似上述的内容,它仅将每个匹配项的单个值捕获到1美元
中。
因为告诉它重复括号
(?:"(. ?)",?)
中的内容一次或多次。所以它将匹配"eee"
字符串,结束然后查找没有找到的"eee"
字符串的重复。
use YAPE::Regex::Explain;
print YAPE::Regex::Explain->new(qr/var strings = \[(?:"(.+?)",?)+/)->explain();
The regular expression:
(?-imsx:var strings = \[(?:"(.+?)",?)+)
matches as follows:
NODE EXPLANATION
----------------------------------------------------------------------
(?-imsx: group, but do not capture (case-sensitive)
(with ^ and $ matching normally) (with . not
matching \n) (matching whitespace and #
normally):
----------------------------------------------------------------------
var strings = 'var strings = '
----------------------------------------------------------------------
\[ '['
----------------------------------------------------------------------
(?: group, but do not capture (1 or more times
(matching the most amount possible)):
----------------------------------------------------------------------
" '"'
----------------------------------------------------------------------
( group and capture to \1:
----------------------------------------------------------------------
.+? any character except \n (1 or more
times (matching the least amount
possible))
----------------------------------------------------------------------
) end of \1
----------------------------------------------------------------------
" '"'
----------------------------------------------------------------------
,? ',' (optional (matching the most amount
possible))
----------------------------------------------------------------------
)+ end of grouping
----------------------------------------------------------------------
) end of grouping
----------------------------------------------------------------------
一个更简单的例子是:
my @m = ('abcd' =~ m/(\w)+/g);
print "@m";
仅打印d
。这是由于:
use YAPE::Regex::Explain;
print YAPE::Regex::Explain->new(qr/(\w)+/)->explain();
The regular expression:
(?-imsx:(\w)+)
matches as follows:
NODE EXPLANATION
----------------------------------------------------------------------
(?-imsx: group, but do not capture (case-sensitive)
(with ^ and $ matching normally) (with . not
matching \n) (matching whitespace and #
normally):
----------------------------------------------------------------------
( group and capture to \1 (1 or more times
(matching the most amount possible)):
----------------------------------------------------------------------
\w word characters (a-z, A-Z, 0-9, _)
----------------------------------------------------------------------
)+ end of \1 (NOTE: because you are using a
quantifier on this capture, only the LAST
repetition of the captured pattern will be
stored in \1)
----------------------------------------------------------------------
) end of grouping
----------------------------------------------------------------------
如果在捕获组上使用量词,则只会使用最后一个实例。
这里有一个有效的方法:
my $str = <<STR;
...
...
var strings = ["aaa","bbb","ccc","ddd","eee"];
...
...
STR
my @matches;
$str =~ m/var strings = \[(.+?)\]/; # get the array first
my $jsarray = $1;
@matches = $array =~ m/"(.+?)"/g; # and get the strings from that
print "@matches";
更新:单行解决方案(虽然不是单个正则表达式)将是:
@matches = ($str =~ m/var strings = \[(.+?)\]/)[0] =~ m/"(.+?)"/g;
但这是高度不可读的imho。