有没有一种快速的方法来找到Ruby中正则表达式的每个匹配?我已经查看了Ruby STL中的Regex对象,并在谷歌上进行了搜索,但一无所获。


当前回答

你可以使用string.scan(your_regex).flatten。如果正则表达式包含组,它将以单个普通数组返回。

string = "A 54mpl3 string w1th 7 numbers scatter3r ar0und"
your_regex = /(\d+)[m-t]/
string.scan(your_regex).flatten
=> ["54", "1", "3"]

Regex也可以是命名组。

string = 'group_photo.jpg'
regex = /\A(?<name>.*)\.(?<ext>.*)\z/
string.scan(regex).flatten

你也可以使用gsub,这只是你想要MatchData的另一种方式。

str.gsub(/\d/).map{ Regexp.last_match }

其他回答

要找到所有匹配的字符串,请使用String的scan方法。

str = "A 54mpl3 string w1th 7 numb3rs scatter36 ar0und"
str.scan(/\d+/)
#=> ["54", "3", "1", "7", "3", "36", "0"]

如果需要,使用Regexp match方法返回的对象类型MatchData:

str.to_enum(:scan, /\d+/).map { Regexp.last_match }
#=> [#<MatchData "54">, #<MatchData "3">, #<MatchData "1">, #<MatchData "7">, #<MatchData "3">, #<MatchData "36">, #<MatchData "0">]

使用MatchData的好处是你可以使用offset这样的方法:

match_datas = str.to_enum(:scan, /\d+/).map { Regexp.last_match }
match_datas[0].offset(0)
#=> [2, 4]
match_datas[1].offset(0)
#=> [7, 8]

如果你想了解更多,请看这些问题:

“如何获得字符串中所有出现Ruby正则表达式的匹配数据?” "支持命名捕获的Ruby正则表达式匹配枚举器" “如何在ruby中找到每个匹配的起点”

阅读Ruby中的特殊变量$&,$',$1,$2也会有帮助。

你可以使用string.scan(your_regex).flatten。如果正则表达式包含组,它将以单个普通数组返回。

string = "A 54mpl3 string w1th 7 numbers scatter3r ar0und"
your_regex = /(\d+)[m-t]/
string.scan(your_regex).flatten
=> ["54", "1", "3"]

Regex也可以是命名组。

string = 'group_photo.jpg'
regex = /\A(?<name>.*)\.(?<ext>.*)\z/
string.scan(regex).flatten

你也可以使用gsub,这只是你想要MatchData的另一种方式。

str.gsub(/\d/).map{ Regexp.last_match }

如果你有一个带组的regexp:

str="A 54mpl3 string w1th 7 numbers scatter3r ar0und"
re=/(\d+)[m-t]/

你可以使用String的scan方法来查找匹配的组:

str.scan re
#> [["54"], ["1"], ["3"]]

找到匹配的模式:

str.to_enum(:scan,re).map {$&}
#> ["54m", "1t", "3r"]

使用scan可以做到这一点:

string.scan(/regex/)

如果你在正则表达式中有capture groups()用于其他目的,建议的String#scan和String#match解决方案是有问题的:

只获取捕获组内的内容; String#match只获得第一个匹配项,拒绝所有其他匹配项; String#matches(建议函数)获取所有匹配项。

在这种情况下,我们需要一个解决方案来匹配正则表达式,而不考虑捕获组。

字符串#匹配项

通过Refinements,你可以猴子修补String类,实现String#匹配,这个方法将在使用细化的类范围内可用。这是一个不可思议的方式猴补丁类在Ruby。

设置

/lib/refinements/string_matches.rb

# This module add a String refinement to enable multiple String#match()s
# 1. `String#scan` only get what is inside the capture groups (inside the parens)
# 2. `String#match` only get the first match
# 3. `String#matches` (proposed function) get all the matches
module StringMatches
  refine String do
    def matches(regex)
      scan(/(?<matching>#{regex})/).flatten
    end
  end
end

用途:命名捕获组

使用

rails c

> require 'refinements/string_matches'

> using StringMatches

> 'function(1, 2, 3) + function(4, 5, 6)'.matches(/function\((\d), (\d), (\d)\)/)
=> ["function(1, 2, 3)", "function(4, 5, 6)"]

> 'function(1, 2, 3) + function(4, 5, 6)'.scan(/function\((\d), (\d), (\d)\)/)
=> [["1", "2", "3"], ["4", "5", "6"]]

> 'function(1, 2, 3) + function(4, 5, 6)'.match(/function\((\d), (\d), (\d)\)/)[0]
=> "function(1, 2, 3)"