我想获取索引以及扫描结果
"abab".scan(/a/)
我不仅要
=> ["a", "a"]
还有那些比赛的索引
[1, 3]
任何建议?
答案 0 :(得分:23)
试试这个:
res = []
"abab".scan(/a/) do |c|
res << [c, $~.offset(0)[0]]
end
res.inspect # => [["a", 0], ["a", 2]]
答案 1 :(得分:6)
根据你期望的行为,这里有一个值得关注的问题。
如果您在/dad/
中搜索"dadad"
,则只会获得[["dad",0]]
,因为scan
会在找到一个匹配时前进到每个匹配的结尾(这是错误的我)。
我想出了这个替代方案:
def scan_str(str, pattern)
res = []
(0..str.length).each do |i|
res << [Regexp.last_match.to_s, i] if str[i..-1] =~ /^#{pattern}/
end
res
end
如果你想要也可以在标准库中使用StringScanner做类似的事情,那么长字符串可能会更快。
答案 2 :(得分:4)
非常类似于@jim所说的并且对于更长的字符串效果更好:
def matches str, pattern
arr = []
while (str && (m = str.match pattern))
offset = m.offset(0).first
arr << offset + (arr[-1] ? arr[-1] + 1 : 0)
str = str[(offset + 1)..-1]
end
arr
end
答案 3 :(得分:1)
令我感到惊讶的是,没有任何类似于String#scan
的方法会返回MatchData
个对象的数组,类似于String#match
。所以,如果你喜欢猴子修补,你可以将它与Todd的解决方案结合起来(1.9中引入了Enumerator
):
class Regexp
def scan str
Enumerator.new do |y|
str.scan(self) do
y << Regexp.last_match
end
end
end
end
#=> nil
/a/.scan('abab').map{|m| m.offset(0)[0]}
#=> [0, 2]