2012-03-02 8 views
10

基本的に質問タイトルに記載されているように、Rubyの文字列にはString#Scanと同等のメソッドがありますが、各一致のリストを返すのではなく、 ?例:Ruby String#scan MatchDataを返すのと同等です

# Matches a set of characters between underscore pairs 
"foo _bar_ _baz_ hashbang".some_method(/_[^_]+_/) #=> [#&ltMatchData "_bar_"&rt, &ltMatchData "_baz_"&rt] 

また、同じような結果を得ることもできます。 Ruby文字列内の "文字列"の位置と範囲を見つけるためにこれを行いたいと思います。 "goodbye"world" "残念ながら"残酷な世界 ""。

答えて

7

MatchData#endposのパラメータをString#matchとすることで、自分で簡単に作成できます。

def matches(s, re) 
    start_at = 0 
    matches = [ ] 
    while(m = s.match(re, start_at)) 
     matches.push(m) 
     start_at = m.end(0) 
    end 
    matches 
end 

そして:

>> matches("foo _bar_ _baz_ hashbang", /_[^_]+_/) 
=> [#<MatchData "_bar_">, #<MatchData "_baz_">] 
>> matches("_a_b_c_", /_[^_]+_/) 
=> [#<MatchData "_a_">, #<MatchData "_c_">] 
>> matches("_a_b_c_", /_([^_]+)_/) 
=> [#<MatchData "_a_" 1:"a">, #<MatchData "_c_" 1:"c">] 
>> matches("pancakes", /_[^_]+_/) 
=> [] 

あなたは可能性があなたが本当にしたい場合は文字列にモンキーパッチこのような何か。

+0

これはまさに私が必要とするものです。ハァー、私はそれのような何かをすることができる方法を考えていたが、私はpos paramについて知らなかった:) – Jwosty

11
memo = [] 
"foo _bar_ _baz_ hashbang".scan(/_[^_]+_/) { memo << Regexp.last_match } 
=> "foo _bar_ _baz_ hashbang" 
memo 
=> [#<MatchData "_bar_">, #<MatchData "_baz_">] 
+3

+1非常に簡潔。そして 'Regexp.last_match'はスレッドローカルなので競合状態に陥ることはありません。 – Kelvin

1

あなたはMatchDataの背中を取得する必要がない場合は、ここでStringScannerを使用して方法です。

require 'strscan' 

rxp = /_[^_]+_/ 
scanner = StringScanner.new "foo _barrrr_ _baz_ hashbang" 
match_infos = [] 
until scanner.eos? 
    scanner.scan_until rxp 
    if scanner.matched? 
    match_infos << { 
     pos: scanner.pre_match.size, 
     length: scanner.matched_size, 
     match: scanner.matched 
    } 
    else 
    break 
    end 
end 

p match_infos 
# [{:pos=>4, :length=>8, :match=>"_barrrr_"}, {:pos=>13, :length=>5, :match=>"_baz_"}] 
関連する問題