这对我来说可能是一个非常基本的错误,但是我已经被困在这个问题上很长时间了,这让我不得不把它推到墙上!
我使用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
。我的代码在哪里出错?
答案 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)/
文档: