为什么 ruby​​ 只返回正则表达式的最后一个匹配项?

R.D*_*.D. 2 ruby regex

我的正则表达式如下(\d+_)*,测试字符串是1_2_3_. Ruby 正确匹配字符串。然而,匹配数据只返回“3_”作为匹配。

例如

irb(main):004:0> /(\d+_)*/.match("1_2_3_")
=> #<MatchData "1_2_3_" 1:"3_">
Run Code Online (Sandbox Code Playgroud)

我希望像 #<MatchData "1_2_3_" 1:"1_", 2:"2_", 3:"3_">

Tim*_*ker 5

该组的每次新重复都会覆盖之前的匹配。所有正则表达式引擎都以这种方式工作。据我所知,只有 .NET 正则表达式引擎提供了一种访问重复组的所有匹配项(所谓的“捕获”)的方法。

想象一下发生了什么。在正则表达式中,每对括号构建一个捕获组;它们从左到右编号。所以在/(\d+_)*/,(\d+_)正在捕获组号 1。

现在,如果您将该正则表达式应用于1_2_,会发生什么?

  • (\d+_) 火柴 1_
  • 1_存储为第一个捕获组的内容。您现在可以访问\1以查看这些内容。
  • *告诉正则表达式引擎重试从当前位置匹配。
  • (\d+_) 现在匹配 2_
  • 该文本 ,2_再次需要存储在组号 1/backreference 中\1。所以它会覆盖那里的任何内容。

要在 Ruby 中获得所需的结果,您需要进行两次正则表达式匹配:/(?:\d+_)*/针对整体匹配和/\d+_/针对每个单个匹配:

irb(main):001:0> s = "1_2_3_"
=> "1_2_3_"
irb(main):009:0> s.match(/(?:\d+_)*/)
=> #<MatchData "1_2_3_">
irb(main):007:0> s.scan(/\d+_/)
=> ["1_", "2_", "3_"]
Run Code Online (Sandbox Code Playgroud)