web-dev-qa-db-ja.com

Ruby正規表現グループの一致、1行の変数の割り当て

現在、文字列を複数の変数にrexpしようとしています。文字列の例:

ryan_string = "RyanOnRails: This is a test"

3つのグループで、この正規表現と一致させました。

ryan_group = ryan_string.scan(/(^.*)(:)(.*)/i)

各グループにアクセスするには、次のようにする必要があります。

ryan_group[0][0] (first group) RyanOnRails
ryan_group[0][1] (second group) :
ryan_group[0][2] (third group) This is a test

これはかなりばかげているようで、私は何か間違ったことをしているように感じます。私はこのようなことをすることができると期待されるでしょう:

g1, g2, g3 = ryan_string.scan(/(^.*)(:)(.*)/i)

これは可能ですか?それとも私がそれをやっているよりも良い方法がありますか?

112
ryanjones

あまり意味がないので、scanは必要ありません。 String#matchを使用してMatchDataオブジェクトを返し、#capturesを呼び出してキャプチャの配列を返すことができます。このようなもの:

#!/usr/bin/env Ruby

string = "RyanOnRails: This is a test"
one, two, three = string.match(/(^.*)(:)(.*)/i).captures

p one   #=> "RyanOnRails"
p two   #=> ":"
p three #=> " This is a test"

一致するものが見つからない場合、String#matchはnilを返すので、このようなものがより適切に機能することに注意してください。

if match = string.match(/(^.*)(:)(.*)/i)
  one, two, three = match.captures
end

scanはこれにはほとんど意味がありません。それはまだ仕事をします、あなたは最初に返された配列を平らにする必要があります。 one, two, three = string.scan(/(^.*)(:)(.*)/i).flatten

183
Lee Jarvis

代わりに Match または=〜を使用すると、単一の一致が得られ、一致データに同じ方法でアクセスするか、特別な一致変数$ 1、$ 2、$ 3を使用できます

何かのようなもの:

if ryan_string =~ /(^.*)(:)(.*)/i
   first = $1
   third = $3
end
41
Rado

キャプチャした一致に名前を付けることができます

string = "RyanOnRails: This is a test"
/(?<one>^.*)(?<two>:)(?<three>.*)/i =~ string
puts one, two, three

文字列と正規表現の順序を逆にすると機能しません。

27
toonsend

良いアイデアかどうかを判断する必要がありますが、Ruby regexpは(自動的に)ローカル変数を定義できます

この機能が素晴らしいのか、まったく夢中なのかはまだわかりませんが、正規表現でローカル変数を定義できます。

ryan_string = "RyanOnRails: This is a test"
/^(?<webframework>.*)(?<colon>:)(?<rest>)/ =~ ryan_string
# This defined three variables for you. Crazy, but true.
webframework # => "RyanOnRails"
puts "W: #{webframework} , C: #{colon}, R: #{rest}"

http://Ruby-doc.org/core-2.1.1/Regexp.html を見て、「ローカル変数」を検索してください)。

注:コメントで指摘したように、@ toonsend( https: //stackoverflow.com/a/21412455 )。私は「盗む」とは思いませんが、もしあなたが称賛と公正であり、最初の答えを尊重したいなら、気軽に:)動物に害を与えないことを望みます。

6
Felix

scan()は、文字列内で正規表現に一致しないすべての一致を検出するため、予想されるようにグループの配列を返す代わりに、配列の配列を返します。

おそらくmatch()を使用してから、MatchData#capturesを使用してキャプチャの配列を取得することをお勧めします。

g1, g2, g3 = ryan_string.match(/(^.*)(:)(.*)/i).captures

ただし、次の場合はscan()でこれを行うこともできます。

g1, g2, g3 = ryan_string.scan(/(^.*)(:)(.*)/i)[0]
3
Andrew Clark