锚定含hello行首的正则表达式匹配失效问题排查
Perl正则无法匹配行首"hello"返回"not found"的原因分析
需求说明
需使用锚定到包含“hello”的任意行开头的正则表达式,按字符串中出现顺序找到第一个“hello”并打印其字符位置,接着找到下一个“hello”并打印位置。
问题描述
尝试以下两段Perl代码均返回“not found”,无法正常工作:
尝试1代码
$line = "\n hi\n hiya \n hello\n hi \n hello2"; $match = $line =~ m/^\s*(hello)/; if (!$match) { die("not found\n"); } print "found at pos: " . pos($line) . "\n"; $line = $'; $match = $line =~ m/^\s*(hello)/; if (!$match) { die("not found\n"); } print "found at pos: " . pos($line) . "\n";
结果:not found
尝试2代码
$line = "\n hi\n hiya \n hello\n hi \n hello2"; $match = $line =~ m/\A\s*(hello)/; if (!$match) { die("not found\n"); } $line = $'; $match = $line =~ m/\A\s*(hello)/; if (!$match) { die("not found\n"); } print "found at pos: " . pos($line) . "\n";
结果:not found
原因分析
锚点行为误解
- 尝试1中的
^锚点,默认仅匹配整个字符串的开头,而非每行开头。要让^匹配每行起始位置,必须添加/m(多行模式)修饰符。 - 尝试2中的
\A锚点,无论是否开启多行模式,都只会匹配整个字符串的绝对起始位置,完全不可能命中中间行的"hello"。
- 尝试1中的
字符串截断的逻辑错误
- 将
$line替换为$'(匹配后的剩余字符串)后,后续正则的锚点只会匹配新字符串的开头,而原字符串中第二个"hello"所在的行并非新字符串的行首,自然无法匹配。
- 将
正确实现方式
使用全局匹配(/g)结合多行模式(/m),遍历所有符合条件的匹配项并计算起始位置:
my $line = "\n hi\n hiya \n hello\n hi \n hello2"; while ($line =~ /^\s*(hello)/gm) { # pos()返回匹配结束的位置,减去"hello"的长度得到起始位置 print "found at pos: " . (pos($line) - length($1)) . "\n"; }
内容的提问来源于stack exchange,提问作者Bill Moore
相关产品推荐
相关产品推荐

