Ruby正则表达式非捕获组

时间:2016-02-17 16:14:22

标签: ruby regex

我试图从字符串中获取ID号,比如说

id/number/2000GXZ2/ref=sr
使用

(?:id\/number\/)([a-zA-Z0-9]{8})

由于某些原因,非捕获组不起作用,给我:

id/number/2000GXZ2

3 个答案:

答案 0 :(得分:9)

正如其他人所提到的,非捕获群体仍然计入整体匹配。如果你不想在你的比赛中使用这个部分,请使用lookbehind。 Rubular example

(?<=id\/number\/)([a-zA-Z0-9]{8})
  

(?&lt; = pat) - 正向后观断言:确保前面的字符匹配pat,但不包括匹配文本中的那些字符

Ruby Doc Regexp

此外,在这种情况下,id号码周围的捕获组是不必要的。

答案 1 :(得分:2)

你有:

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"

应该返回整个匹配,而不仅仅是捕获组1的内容。有几种方法可以解决这个问题。首先考虑不使用捕获组的那些。

@ 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:]]。实际上,如果所有条目都具有您的示例的形式,您可以使用:

r = /
    \d          # match a digit
    [A-Z0-9]{7} # match >= 0 capital letters or digits
    /x

str[r]
  #=> "2000GXZ2"

如果要匹配的子字符串后面总是后跟非字母数字字符,则可以将{8}替换为+,将{7}替换为*

另一种方法是保留捕获组。一个简单的方法是:

r = /
    id\/number\/     # match string
    ([[:alnum:]]{8}) # match >= 1 alphameric characters in capture group 1
    /x

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"

答案 2 :(得分:0)

这是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

也就是说,当您使用(?:)以及使用{的其他ruby部分时,使用(?<=)替换为非捕获组的scan会使您受益匪浅1}} S上。