正規表現のすべての出現に一致させる方法


586

Rubyで正規表現のすべての一致をすばやく見つける方法はありますか?Ruby STLのRegexオブジェクトを調べ、Googleで検索してみたが役に立たなかった。


3
私はこれを読んで、どのようにしてすべての正規表現パターンの文字列を検索でき、ひどく混乱しました...
Hugoagogo

回答:


821

を使用scanしてトリックを行う必要があります:

string.scan(/regex/)

9
しかし、この事件に隣接しているのは何ですか?"マッチミー!"。scan(/.../)= ["mat"、 "ch" "me!" ]、ただし/.../のすべての出現は["mat"、 "atc"、 "tch"、 "ch"、...]
Michael Dickens

13
そうではありません。/.../は通常の貪欲な正規表現です。一致するコンテンツをバックトラックしません。怠惰な正規表現を使用することもできますが、それでもおそらく十分ではありません。正規表現ドキュメントruby-doc.org/core-1.9.3/Regexp.htmlを見て、正規表現を正しく表現してください:)
Jean

49
これはRuby WTFのようです...なぜこれが他の正規表現のものと正規表現の代わりに文字列にあるのですか?それは
正規表現の

9
それは、RegexではなくStringで定義および呼び出されているためだと思います...しかし、実際には意味があります。Regex#matchを使用してすべての一致をキャプチャし、キャプチャされたグループを反復する正規表現を記述できます。ここでは、部分一致関数を記述して、それを特定の文字列に複数回適用する必要があります。これはRegexpの責任ではありません。理解を深めるためにスキャンの実装を確認することをお勧めします:ruby-doc.org/core-1.9.3/String.html#method-i-scan
Jean

9
@MichaelDickens:この場合、を使用できます/(?=(...))/
Konrad Borowski、2014年

67

一致するすべての文字列を検索するには、Stringのscanメソッドを使用します。

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

MatchDataRegexp matchメソッドによって返されるオブジェクトのタイプであるが必要な場合は、以下を使用します。

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]

詳細については、次の質問をご覧ください。

特殊変数について読んで$&$'$1$2Rubyであまりにも参考になります。


12

グループの正規表現がある場合:

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"]

str.scan(/\d+[m-t]/) # => ["54m", "1t", "3r"]より慣用的ですstr.to_enum(:scan,re).map {$&}
ティンマン

多分あなたは誤解しました。私が返信したユーザーの例の正規表現は次のとおり/(\d+)[m-t]/でした:/\d+[m-t]/書き込むことre = /(\d+)[m-t]/; str.scan(re)はありません:同じですstr.scan(/(\d+)[mt]/)が#>が得られますが、質問は[["" 54 "], [" 1 "], [" 3 "]]ありませんでした"54m", "1t", "3r"]。表現(グループを離れる)、どうすればよいですか?この意味で、読んで少し不可解な困難にもかかわらず可能な解決策であった:str.to_enum(:scan,re).map {$&}
MVP

-1

使用できます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"]

正規表現は名前付きグループにすることもできます。

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

gsubMatchDataが必要な場合は、を使用することもできます。

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

からグループを削除すると、your_regex = /(\d+)[m-t]/を使用する必要がなくなりますflatten。最後の例ではlast_match、この場合はおそらく安全ですが、グローバルであり、を呼び出す前に正規表現が一致した場合は上書きされる可能性がありますlast_match。その代わりに、使用におそらく安全ですstring.match(regex).captures # => ["group_photo", "jpg"]string.scan(/\d+/) # => ["54", "3", "1", "7", "3", "0"]パターンやニーズに応じて、他の回答のように。
Tin Man
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.