正则表达式匹配后未定义Perl $ 1变量

时间:2014-09-28 11:17:28

标签: regex perl

这对我来说可能是一个非常基本的错误,但是我已经被困在这个问题上很长时间了,这让我不得不把它推到墙上!

我使用Perl循环遍历Python代码文件并识别其变量。我使用Perl正则表达式在空格之间挑选出字母数字字符的子串。正则表达式工作正常并标识匹配所属的行,但是当我尝试返回与正则表达式匹配的实际子字符串时,捕获变量$1未定义。

这是我的正则表达式:

if ($line =~ /.*\s+[a-zA-Z0-9]+\s+.*/) {
    print $line;
    print $1;
}

这是错误:

x = 1
Use of uninitialized value $1 in print at ./vars.pl line 7, <> line 2.

据我了解,$1应该返回x。我的代码在哪里出错?

2 个答案:

答案 0 :(得分:7)

您没有捕获结果:

if ($line =~ /.*\s+([a-zA-Z0-9]+)\s+.*/) {

如果你想匹配像x = 1这样的行并得到它的两个部分,你需要匹配并用括号捕获它们。原油方法:

if ( $line =~ /^\s* ( \w+ ) \s* = \s* ( \w+ ) \s* $/msx ) {
    my $var = $1;
    my $val = $2;
}

答案 1 :(得分:4)

answer给出了正确的Leeft:您需要使用括号来捕获字符串。我想提一些其他的事情。在您的代码中:

if ($line =~ /.*\s+[a-zA-Z0-9]+\s+.*/) {
    print $line;
    print $1;
}

您正在使用.*\s+围绕您的匹配。这不太可能按照你的想法行事。除非您正在捕获字符串(或使用$&捕获整个匹配项),否则您永远不需要将.*m//一起使用。默认情况下,匹配不会锚定,并且将匹配字符串中的任何位置。要锚定匹配项,您必须使用^$。 E.g:

if ('abcdef' =~ /c/)      # returns true
if ('abcdef' =~ /^c/)     # returns false, match anchored to beginning
if ('abcdef' =~ /c$/)     # returns false, match anchored to end
if ('abcdef' =~ /c.*$/)   # returns true

正如您在上一个示例中所看到的,使用.*是非常多余的,要获得匹配,您只需删除锚点。或者如果你想捕获整个字符串:

if ('abcdef' =~ /(c.*)$/) # returns true, captures 'cdef'

您也可以使用包含整个匹配的$&,无论括号如何。

您可能正在使用\s+来确保您不匹配部分字词。您应该知道有一个名为单词边界的转义序列\b。这是一个零长度断言,用于检查周围的字符是单词还是非单词。

'abc cde fgh' =~ /\bde\b/     # no match
'abc cde fgh' =~ /\bcde\b/    # match
'abc cde fgh' =~ /\babc/      # match
'abc cde fgh' =~ /\s+abc/     # no match! there is no whitespace before 'a'

正如您在上一个示例中所看到的,使用\s+在字符串的开头或结尾处失败。请注意\b也会部分匹配可能属于单词的非单词字符,例如:

'aaa-xxx' =~ /\bxxx/          # match

您必须决定是否需要此行为。如果不这样做,使用\s的替代方法是使用双重否定的情况:(?!\S)。这是一个零长度负向前瞻断言,寻找非空白。对于空白和字符串结尾都是如此。使用后视来检查另一侧。

最后,您使用的是[a-zA-Z0-9]。这可以替换为\w,但\w还包括下划线_(以及其他字词)。

所以你的正则表达式变成了:

/\b(\w+)\b/

或者

/(?<!\S)(\w+)(?!\S)/

文档: