2017-04-10 14 views

答えて

3

に標準ハックは以下のとおりです。

"Einstein".enum_for(:scan, /(?=in)/).map { Regexp.last_match.offset(0).first } 
#=> [1, 6] 
+0

ニース、トーク。 '' nnnn ".enum_for(:scan、/nn/).map {Regexp.last_match.offset(0).first}#=> [0、2]'に注意してください。 '[0、1、2]'が目的の戻り値であれば、正規表現( '/ nn /')を '/(?= nn)/'に変更します。 –

+0

良い点、@Cary。私はほとんどの場合、2番目のものを更新したいと思います。 – tokland

2
def indices_of_matches(str, target) 
    sz = target.size 
    (0..str.size-sz).select { |i| str[i,sz] == target } 
end 

indices_of_matches('Einstein', 'in') 
    #=> [1, 6] 
indices_of_matches('nnnn', 'nn') 
    #=> [0, 1, 2] 

第二の例は、私がオーバーラップした文字列の治療について行わ仮定を反映しています。重複している文字列を考慮しない場合(つまり、2番目の例では[0, 2]が望ましい戻り値です)、この回答は明らかに不適切です。

+0

シンプルでクリーンな、おそらく私はこれで行くだろう。 – tokland

2

これはグローバル値に頼らないという利点をもたらし、より詳細なソリューションです:

def indices(string, regex) 
    position = 0 
    Enumerator.new do |yielder| 
    while match = regex.match(string, position) 
     yielder << match.begin(0) 
     position = match.end(0) 
    end 
    end 
end 

p indices("Einstein", /in/).to_a 
# [1, 6] 

それはEnumeratorを出力するので、あなたもn最初のインデックスを取る遅延したり、単にそれを使用することができます。

あなただけのインデックスよりも多くの情報が必要な場合があります場合にも、あなたがMatchDataEnumeratorを返し、指標を抽出できたが:

def matches(string, regex) 
    position = 0 
    Enumerator.new do |yielder| 
    while match = regex.match(string, position) 
     yielder << match 
     position = match.end(0) 
    end 
    end 
end 

p matches("Einstein", /in/).map{ |match| match.begin(0) } 
# [1, 6] 

@Caryで説明した動作を得るために、あなたは最後に取って代わる可能性ライン内のブロックposition = match.begin(0) + 1

関連する問題