有没有办法在没有无限循环的情况下做到这一点?
while((my $var) = $string =~ /regexline(.+?)end/g) {
print $var;
}
这会导致无限循环,可能是因为直接从while内的正则表达式中分配var会每次都返回“true”?
我知道我可以这样做:
while($string =~ /regexline(.+?)end/g) {
my $var = $1;
print $var;
}
但是我希望能省下一条线。是否有我可以使用的正则表达式修饰符或类似的东西?
(另外,如果我想搜索它,这个符号/技巧实际上是什么叫:
(my $var) = $string =~ /regex/;
谢谢!
答案 0 :(得分:10)
在标量上下文中,带有/g
修饰符的正则表达式将充当迭代器,并在没有更多匹配项时返回false值:
print "$1\n" while "abacadae" =~ /(a\w)/g; # produces "ab","ac","ad","ae"
通过while
表达式中的赋值,您将在列表上下文中评估正则表达式。现在你的正则表达式不再像迭代器那样,它只返回匹配列表。如果列表不为空,则计算结果为真值:
print "$1\n" while () = "abacadae" =~ /(a\w)/g; # infinite "ae"
要解决此问题,您可以从while语句中取出赋值,并使用内置$1
变量在循环内进行赋值?
while ($string =~ /regexline(.+?)end/g) {
my $var = $1;
print $var;
}
答案 1 :(得分:8)
Perl regular expressions tutorial说:
在标量上下文中,对字符串的连续调用将使//从匹配跳转到匹配,跟踪字符串中的位置。
可是:
在列表上下文中,// g返回匹配分组的列表,如果没有分组,则返回整个正则表达式的匹配列表。
也就是说,在列表上下文中//g
一次返回一个包含所有捕获匹配项的数组(之后你将丢弃除第一个之外的所有匹配项),然后每次循环执行时都重复执行(即永远)。
因此,您无法在循环条件中使用列表上下文赋值,因为它不能执行您想要的操作。
如果您坚持使用列表上下文,则可以改为:
foreach my $var ($string =~ /regexline(.+?)end/g) {
print $var;
}
答案 2 :(得分:8)
有没有办法在没有无限循环的情况下做到这一点?
是。使用foreach()而不是while()循环:
foreach my $var ($string =~ /regexline(.+?)end/g) {
如果我想搜索它,这个符号/技巧实际上是什么?
在列表上下文中称为匹配。它在“perldoc perlop”中描述:
g修饰符指定全局模式匹配 - 即在字符串中尽可能多地匹配。它的行为取决于上下文。在列表上下文中......
答案 3 :(得分:1)
在这种情况下,您无法避免在不改变行为的情况下使用全局变量。
while ($string =~ /regexline(.+?)end/g) {
my $var = $1;
...
}
如果您只有一次捕获,则可以通过一次查找所有匹配来避免使用全局变量。
for my $var ($string =~ /regexline(.+?)end/g) {
...
}
第二版的额外费用通常可以忽略不计。
答案 4 :(得分:0)
使用较少的代码可以通过多种方式实现此目的。
假设您有一个名为lines.txt的文件:
regexlineabcdefend
regexlineghijkend
regexlinelmnopend
regexlineqrstuend
This line does not match
Neither does this
regexlinevwxyzend
并且您想要提取与正则表达式匹配的部分,即“正则表达式”和“结束”之间的行块。一个简单的Perl脚本是:
while (<STDIN>) {
print "$1\n" if $_ =~ /regexline(.+?)end/
}
像这样运行
$ perl match.pl < lines.txt
你得到了
abcdef
ghijk
lmnop
qrstu
vwxyz
你甚至可以在命令行上完成整个事情!
$ perl -nle'print $ 1 if $ _ =〜/ regexline(。+?)end /'&lt; lines.txt ABCDEF ghijk lmnop qrstu VWXYZ
就你的第二个问题而言,我不确定是一个特殊的Perl名称。
答案 5 :(得分:0)
我认为你最好的选择就是在循环中替换$ string ......所以:
while((my $var) = $string =~ /regexline(.+?)end/g) {
$string =~ s/$var//;
print $var . "\n";
}
答案 6 :(得分:0)
我不知道你打算用这个版画做什么,但这是一个很好的方法:
say for $string =~ /regex(.+?)end/g;
for(与foreach相同)将正则表达式匹配扩展为捕获组列表,并打印它们。像这样工作:
@matches = $string =~ /regex(.+?)end/g;
say for (@matches);
while
有些不同。由于它使用标量上下文,因此不会将捕获组加载到内存中。
say $1 while $string =~ /regex(.+?)end/g;
除了我们不需要使用转换变量$var
之外,它会执行类似原始代码的操作,我们只需立即打印它。