如何在Perl中获得正则表达式的完美匹配?

时间:2011-10-11 14:54:25

标签: perl

我要匹配一个存储在变量中的正则表达式:

#!/bin/env perl

use warnings;
use strict;
my $expr = qr/\s*(\w+(\[\d+\])?)\s+(\w+(\[\d+\])?)/sx;
$str = "abcd[3] xyzg[4:0]";
if ($str =~ m/$expr/) {
    print "\n%%%%%%%%% $`-----$&-----$'\n";
}
else {
    print "\n********* NOT MATCHED\n";
}

但是我在$&如

%%%%%%%%% -----abcd[3] xyzg-----[4:0]

但是期待,它不应该进入if子句。 目的是:

if $str = "abcd xyzg" => %%%%%%%%% -----abcd xyzg-----            (CORRECT)
if $str = "abcd[2] xyzg" => %%%%%%%%% -----abcd[2] xyzg-----      (CORRECT)
if $str = "abcd[2] xyzg[3] => %%%%%%%%% -----abcd[2] xyzg[3]----- (CORRECT)
if $str = "abcd[2:0] xyzg[3] => ********* NOT MATCHED             (CORRECT)
if $str = "abcd[2:0] xyzg[3:0] => ********* NOT MATCHED           (CORRECT)
if $str = "abcd[2] xyzg[3:0]" => ********* NOT MATCHED            (CORRECT/INTENDED)

但输出为%%%%%%%%% -----abcd[2] xyzg-----[3:0] (WRONG) 或者更好地说这不是故意的。 在这种情况下,它应该/ my_expectation转到else块。 即使我不知道,为什么 $& 取一部分字符串( abcd [2] xyzg )和 $' [3:0] 如何? 它应该匹配完整,而不是像上面那样的部分。如果没有,则不应转到 if 子句。

任何人都可以帮我改变我的$ expr模式,以便我可以拥有预期的目标吗?

2 个答案:

答案 0 :(得分:4)

默认情况下,Perl正则表达式只查找给定字符串的匹配子字符串。为了强制对整个字符串进行比较,您需要指明正则表达式从字符串的开头开始,并在结尾处使用^$结束:

my $expr = qr/^\s*(\w+(\[\d+\])?)\s+(\w+(\[\d+\])?)$/;

(另外,没有理由拥有/x修饰符,因为你的正则表达式不包含任何文字空格或#字符,并且/s修饰符没有理由,因为你没有使用.。)

编辑:如果你不希望正则表达式匹配整个字符串,但是你希望它拒绝匹配部分后跟“[0:0]”之类的东西,最简单的方法就是使用前瞻:

my $expr = qr/^\s*(\w+(\[\d+\])?)\s+(\w+(\[\d+\]|(?=[^[\w])|$ ))/x;

这将匹配采用以下形式的任何内容:

  • 字符串的开头(评论中的示例似乎暗示您想要)
  • 零个或多个空格字符
  • 一个或多个单词字符
  • 可选:[,一个或多个数字,]
  • 一个或多个空白字符
  • 一个或多个单词字符
  • 以下之一,按优先级降序排列:
      • [,一个或多个数字,]
      • 一个空字符串后跟(但不包括!)一个既不是[也不是单词字符的字符(排除单词字符是为了防止正则表达式引擎在“a[0] bc[1:2]”上成功仅匹配“a[0] b”。)
      • 字符串的结尾(在$之后需要一个空格以防止它与以下)合并以形成特殊变量的名称,这需要重新引入{{1}选项。)

您是否还有其他需要满足的未说明要求?

答案 1 :(得分:1)

简短的回答是你的正则表示错误 如果没有您完全解释您的需求,我们无法为您解决这个问题,并且社区不会完全为您的目的编写正则表达式,因为这只是一个本地化的问题,只能帮助您这一次。

你需要问一些关于正则表达式的更一般的问题,我们可以向你解释,这将有助于你修复正则表达式,并帮助其他人修复它们。

当您在测试正则表达式时遇到问题,这是我的一般答案。使用正则表达式工具,例如regex buddy

所以我要给出一个关于你在这里忽略的具体答案:
让我们让这个例子更小: 您的模式为a(bc+d)?。它将匹配:abcd abccd等。虽然在bcd的情况下它不匹配bzd也不匹配abzd,但它仅匹配{{1}因为整个a组是可选的。同样,它会将bc+dabcbcd匹配,从而删除无法匹配的整个可选组(在第二个a处)。

正则表达式将匹配尽可能多的字符串,并在它们匹配某些内容并满足整个模式时返回真正的匹配。如果你做了一些可选的东西,当他们必须在它出现和匹配时必须包括它时,它们会把它留下来。

这是你尝试过的:
  b
首先,此处不需要qr/\s*(\w+(\[\d+\])?)\s+(\w+(\[\d+\])?)/sxs修饰符 其次,这个正则表达式可以匹配:
任何或没有空格后跟
至少包含一个字母字符的单词后跟
可选地,带有至少一个数字(例如[0]或[9999])的分组方括号括号后跟 至少有一个空格,后跟
至少包含一个字母字符的单词后跟
可选的方括号括号,至少有一位数。

显然,当你要求它匹配x时,冒号结束abcd[0] xyzg[0:4]模式但不满足\d+所以它会回溯整个组,然后愉快地发现组是可选的。因此,如果不匹配最后一个可选组,则您的模式已成功匹配。