我尝试使用正则表达式解析网页的子集以获得乐趣。直到我遇到以下问题才很有趣。我有一个如下所示的段落;
foo: 1, 2, 3, 4 and 5.
bar: 1, 2 and 3.
我要做的是,通过应用以下正则表达式获取以foo:
开头的段落第一行中的数字:
foo:(?:\s(\d)(?:,|\sand|\.))+
这与上面的字符串匹配,但它只捕获最后一次出现的5
捕获组。
如何使用单个正则表达式模式捕获以foo:
开头的段落中的所有数字,直到第一次出现.
为止。
答案 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 不同,它允许可变长度匹配。