【发布时间】:2011-04-01 00:24:29
【问题描述】:
我想获取索引以及扫描结果
"abab".scan(/a/)
我想要的不仅仅是
=> ["a", "a"]
还有那些匹配的索引
[1, 3]
有什么建议吗?
【问题讨论】:
-
您好 - 对大量垃圾邮件感到抱歉,但如果您还没有到 area51.stackexchange.com/proposals/74083/korean-language 可以使用您!
我想获取索引以及扫描结果
"abab".scan(/a/)
我想要的不仅仅是
=> ["a", "a"]
还有那些匹配的索引
[1, 3]
有什么建议吗?
【问题讨论】:
试试这个:
res = []
"abab".scan(/a/) do |c|
res << [c, $~.offset(0)[0]]
end
res.inspect # => [["a", 0], ["a", 2]]
【讨论】:
$~ 这样的稍微神秘的特殊变量,那么 Regexp.last_match 是等价的。即你可以说Regexp.last_match.offset(0)[0]
Regexp.last_match.offset(0).first
MatchData#offset 和 Regexp::last_match
这里有一个问题需要注意,具体取决于您所期望的行为。
如果您在"dadad" 中搜索/dad/,您只会得到[["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 做类似的事情,对于长字符串可能会更快。
【讨论】:
与@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
【讨论】:
令我惊讶的是,没有任何类似于String#scan 的方法可以返回MatchData 对象的数组,类似于String#match。所以,如果你喜欢猴子补丁,你可以将它与 Todd 的解决方案结合起来(Enumerator 在 1.9 中引入):
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]
【讨论】: