我正在尝试从字符串中获取ID号码,比如说
id/number/2000GXZ2/ref=sr
使用
(?:id\/number\/)([a-zA-Z0-9]{8})
由于某种原因,非捕获组没有起作用,给出了以下结果:
id/number/2000GXZ2
正如其他人所提到的,非捕获组仍然计入总匹配次数。如果您不想在匹配中包含该部分,请使用后顾(lookbehind)。
Rubular 示例(?<=id\/number\/)([a-zA-Z0-9]{8})
(?<=pat) - 正向零宽断言:确保前面的字符与 pat 匹配,但不将这些字符包含在匹配文本中。此外,在这种情况下,id号码周围的捕获组是不必要的。
您拥有:
str = "id/number/2000GXZ2/ref=sr"
r = /
(?:id\/number\/) # match string in a non-capture group
([a-zA-Z0-9]{8}) # match character in character class 8 times, in capture group 1
/x # extended/free-spacing regex definition mode
然后(使用 String#[]):
str[r]
#=> "id/number/2000GXZ2"
返回整个匹配,而不仅仅是第一个捕获组的内容。有几种方法可以解决这个问题。首先考虑不使用捕获组的方法。
@jacob.m 建议使用正向后顾(稍微修改了他的代码)来处理第一个部分:
r = /
(?<=id\/number\/) # match string in positive lookbehind
[[:alnum:]]{8} # match >= 1 alphameric characters
/x
str[r]
#=> "2000GXZ2"
r = /
id\/number\/ # match string
\K # forget everything matched so far
[[:alnum:]]{8} # match 8 alphanumeric characters
/x
str[r]
#=> "2000GXZ2"
\K
在匹配长度可变的情况下特别有用,因为(在Ruby中)正向后瞻不适用于可变长度的匹配。[A-Z0-9]+
而非[[:alnum:]]
(尽管后者包括Unicode字母,而不仅仅是英文字母)。实际上,如果所有条目都具有您的示例形式,则可能能够使用:r = /
\d # match a digit
[A-Z0-9]{7} # match >= 0 capital letters or digits
/x
str[r]
#=> "2000GXZ2"
r = /
id\/number\/ # match string
([[:alnum:]]{8}) # match >= 1 alphameric characters in capture group 1
/x
str =~ r
str[r, 1] #=> "2000GXZ2"
另外,您可以使用String#sub方法将整个字符串替换为捕获组的内容:
r = /
id\/number\/ # match string
([[:alnum:]]{8}) # match >= 1 alphameric characters in capture group 1
.* # match the remainder of the string
/x
str.sub(r, '\1') #=> "2000GXZ2"
str.sub(r, "\\1") #=> "2000GXZ2"
str.sub(r) { $1 } #=> "2000GXZ2"
这是关于 Ruby Regexp
的匹配一致性问题。有些 Regexp
风格的方法会返回全局匹配,而其他方法则会返回指定的匹配。
在这种情况下,我们可以使用一个方法来获得您想要的行为,那就是 scan
。
我认为没有人在这里实际上提到如何让您最初打算的 Regexp
正常工作,即获取仅捕获匹配项。要做到这一点,您可以使用以下方式使用原始模式的 scan
方法:
test_me.rb
test_string="id/number/2000GXZ2/ref=sr"
result = test_string.scan(/(?:id\/number\/)([a-zA-Z0-9]{8})/)
puts result
2000GXZ2
话虽如此,但是将非捕获组的 (?:)
替换为正向零宽断言的 (?<=)
,无论是在使用 scan
还是其他使用 Regexp
的 Ruby 部分,都会对您有所裨益。
id/number/2000GXZ2/ref=sr
?(哪一部分) - Shafizadeh