Ruby正则表达式非捕获组

AKa*_*pun 7 ruby regex

我试图从字符串中获取id号码

id/number/2000GXZ2/ref=sr
Run Code Online (Sandbox Code Playgroud)

运用

(?:id\/number\/)([a-zA-Z0-9]{8})
Run Code Online (Sandbox Code Playgroud)

出于某种原因,非捕获组没有工作,给我:

id/number/2000GXZ2
Run Code Online (Sandbox Code Playgroud)

jac*_*umb 10

正如其他人所提到的,非捕获组仍然计入整体匹配.如果你不希望你的比赛中的那个部分使用lookbehind. Rubular例子

(?<=id\/number\/)([a-zA-Z0-9]{8})
Run Code Online (Sandbox Code Playgroud)

(?<= pat) - 正面的lookbehind断言:确保前面的字符匹配pat,但不包括匹配文本中的那些字符

Ruby Doc Regexp

此外,在这种情况下,不需要围绕id号的捕获组.


Car*_*and 6

你有:

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
Run Code Online (Sandbox Code Playgroud)

然后(使用String#[]):

str[r]
  #=> "id/number/2000GXZ2"
Run Code Online (Sandbox Code Playgroud)

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

@jacob.m 建议将第一部分放在积极的回顾中(从他的代码中稍作修改):

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

str[r]
  #=> "2000GXZ2"
Run Code Online (Sandbox Code Playgroud)

另一种选择是:

r = /
    id\/number\/   # match string
    \K             # forget everything matched so far
    [[:alnum:]]{8} # match 8 alphanumeric characters
    /x

str[r]
  #=> "2000GXZ2"
Run Code Online (Sandbox Code Playgroud)

\K 当要忘记的匹配是可变长度时特别有用,因为(在 Ruby 中)积极的lookbehinds 不适用于可变长度匹配。

对于这两种方法,如果要匹配的部分仅包含数字和大写字母,您可能需要使用[A-Z0-9]+代替[[:alnum:]](尽管后者包括 Unicode 字母,而不仅仅是来自英文字母的字母)。事实上,如果所有条目都具有您的示例的形式,您可能可以使用:

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

str[r]
  #=> "2000GXZ2"
Run Code Online (Sandbox Code Playgroud)

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

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

str =~ r
str[r, 1] #=> "2000GXZ2"
Run Code Online (Sandbox Code Playgroud)

或者,您可以使用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"
Run Code Online (Sandbox Code Playgroud)