Ruby正则表达式多次重复捕获

时间:2018-03-10 23:38:44

标签: ruby regex

我尝试使用正则表达式解析网页的子集以获得乐趣。直到我遇到以下问题才很有趣。我有一个如下所示的段落;

foo: 1, 2, 3, 4 and 5.
bar: 1, 2 and 3.

我要做的是,通过应用以下正则表达式获取以foo:开头的段落第一行中的数字:

foo:(?:\s(\d)(?:,|\sand|\.))+

这与上面的字符串匹配,但它只捕获最后一次出现的5捕获组。

如何使用单个正则表达式模式捕获以foo:开头的段落中的所有数字,直到第一次出现.为止。

2 个答案:

答案 0 :(得分:3)

重复捕获组的数据不会在大多数编程语言中单独存储,因此您无法单独引用它们。这是使用\G锚点的正当理由。 \G会导致匹配从上一个匹配结束的位置开始,或者匹配字符串的开头与\A相同。

所以我们需要它的第一个能力:

(?:foo:|\G(?!\A))\s*(\d+)\s*(?:,|and)?

故障:

  • (?:启动非捕获组
    • foo:匹配foo:
    • |
    • \G(?!\A)继续匹配上一场比赛结束的地方
  • ) NCG结束
  • \s*任意数量的空白字符
  • (\d+)匹配并捕获数字
  • \s*任意数量的白人字符
  • (?:,|and)?可选,and

此正则表达式将在输入字符串中与会议foo开始匹配。然后尝试在逗号或and之前找到一个跟随的数字(数字周围允许有空格)。

\K令牌将重置匹配。这意味着它将向引擎发送信号以忘记到目前为止匹配的任何内容(但保留所捕获的内容)然后将光标留在该位置。

我在Rubular正则表达式中使用\K使结果集不具有匹配的字符串但捕获的数字。然而,Rubular似乎工作方式不同,不需要\K。这根本不是必须的。

答案 1 :(得分:0)

这个答案仅使用一个正则表达式,但无可否认地进行了一些预处理和后处理。 (请允许我一点乐趣。我认为这里可能有一些教学价值。)

str = "foo: 1, 2, 34, 4 and 5. and 6."

r = /
    \d+             # match one or more digits
    (?=[^.]+:oof\z) # match one or more digits other than a period, followed
                    # by ":oof" at the end of the string, in a positive lookahead
    /x              # free-spacing regex definition mode

str.reverse.scan(r).join(' ').reverse.split
  #=> ["1", "2", "34", "4", "5"]

步骤如下。

s = str.reverse
  #=> ".6 dna .5 dna 4 ,43 ,2 ,1 :oof"
a  = s.scan r
  #=> ["5", "4", "43", "2", "1"]
b  = a.join(' ')
  #=> "5 4 43 2 1"
c  = b.reverse
  #=> "1 2 34 4 5"
c.split
  #=> ["1", "2", "34", "4", "5"]

如果没有匹配,则返回一个空数组。

那么,为什么所有的逆转呢?这是允许我使用积极的前瞻,与正 lookbehind 不同,它允许可变长度匹配。