1. ホーム
  2. スクリプト・コラム
  3. ルビートピックス

Rubyプログラムにおける正規表現の基本的な使い方に関するチュートリアル

2022-01-30 18:45:18

Rubyの組み込み型のほとんどは、他のプログラミング言語の型と非常によく似ています。主なものは、文字列、整数、浮動小数点数、配列、などなどです。しかし、Ruby、Perl、awkなどのスクリプト言語だけが、組み込みの式型をサポートしています。正規表現はもっとわかりにくいが、非常に強力なテキスト処理ツールである。

正規表現は、指定されたパターンを使って文字列をマッチングさせる簡単な方法です。Rubyでは、2つのスラッシュ/pattern/の間にパターンを記述して正規表現を作成するのが典型的な方法である。

やはりRubyはRubyで、正規表現はオブジェクトであり、オブジェクトのように操作することができる。

例えば、以下のような正規表現を使って、PerlやPythonが含まれる文字列にマッチするパターンを書くことができます。

<! --more-->

/Perl|Python/



フォワードスラッシュの内側にはマッチさせたい2つの文字列があり、それらは"|"で区切られています。このパイプ文字は "左または右" を意味し、このパターンでは Perl または Python を意味します。

また、算術式のように括弧を使うこともできますので、パターンは次のように書くこともできます。

/P(erl|ython)/


また、パターンには繰り返しを指定することもできます。例えば、プラス記号 /ab+c/ は、a の後に 1 つ以上の b が続き、さらに c が続く文字列にマッチします。プラス記号をアスタリスクに置き換えると、 /ab*c/ は、a の後に 0 つ以上の b が続き、さらに c が続く場合にマッチする正規表現が作成されます。

また、パターンに含まれる文字の集合にマッチさせることもできます。よく使われる文字の例としては、空白文字(スペース、タブ、改行など)にマッチする \s 、任意の数字にマッチする \d 、任意の典型的な単語文字にマッチする \w があります。ピリオド(.)は(基本的に)あらゆる文字にマッチします。

これらを組み合わせて、便利な正規表現を作ります。

/\d\d:\d\d:\d\d/ # a time such as 12:34:56
/Perl.*Python/ # Perl, zero or more other chars, then Python
/Perl Python/ # Perl, a space, and Python
/Perl *Python/ # Perl, zero or more spaces, and Python
/Perl +Python/ # Perl, one or more spaces, and Python
/Perl\s+Python/ # Perl, whitespace characters, then Python
/Ruby (Perl|Python)/ # Ruby, a space, and either Perl or Python


一度作ったパターンが使えないと、もどかしいですよね。マッチ演算子=~は、文字列に対して正規表現のマッチを行うために使われる。マッチが成功すれば、=~は最初に成功したマッチの位置を返し、そうでなければnilを返します。つまり、ifやwhileの条件文の中で正規表現を使うことができるのです。たとえば、次のコード・スニペットでは

文字列にPerlまたはPythonのテキストが含まれている場合、メッセージを出力します。

puts "Scripting language mentioned: #{line}" if line =~ /Perl|Python/


PerlとPythonの出現箇所をすべてRubyで置き換えることができます。

line.gsub(/Perl|Python/, 'Ruby')


アイハワーのRuby on Railsハンズオンバイブルから、正規表現で携帯電話の番号を取得する例です。

phone = "139-1234-5678"
if phone =~ /(\d{3})-(\d{4})-(\d{4})/
 start_with = $1
 mid_num = $2
 end_as = $3
end



一般的なルール(通常表示の場合、コードブロック内に配置されます。)

  • /a/ は文字 a にマッチします。   
  • /\? /\ は特殊文字? 特殊文字には、^, $, ? , . , /, \, [, ], {, }, (, ), +, *.   
  • . 任意の文字にマッチします。例えば、/a./ は ab と ac にマッチします。   
  • /[ab]c/matches ac and bc, between [] is the range representing the range of the []. 例 /[a-z]/ , /[a-zA-Z0-9]/.   
  • /[^a-zA-Z0-9]/ は、その範囲に含まれない文字列にマッチします。   
  • 任意の数字に対応する /[d]/
  • /[\w]/ は、任意の文字、数字、または _ を表します。
  • /[\s]/ は、スペース、TAB、改行を含む空白文字です。   
  • /[\D]/, /[\W]/, /[\S]/ は、すべて上記を否定するものです。

高度なルール

  • は0または1文字を表します。/Mrs?˶?˶? /quot;Mr"、 "Mrs" 、 "Mr." 、 "Mrs." と一致します。
  • * は0文字以上を表します。/Hello*/ は "Hello","HelloJack" にマッチします。
  • 1文字以上の場合は+。/a+c/ は "abc", "abbdrec" などにマッチします。
  • /d{3}/数字3文字にマッチします。
  • /d{1,10}/1〜10の数字にマッチします。
  • /d{3,}/3つ以上の数字にマッチします。
  • /([A-Z]\d){5}/ 最初の文字が大文字で、次の4文字が数字である文字列にマッチします。

正規表現操作

StringとRegExpの両方が、=~とmatchのクエリマッチングメソッドをサポートしています。

puts "I can say my name" =~ /name/ #-> 13

a = /name/.match("I can say my name, my name I can say") #-> a is MatchData
puts a[0] #-> name



ご覧のように、マッチングが可能な場合、=~はマッチする文字列の位置を返し、matchはMatchDataオブジェクトを返します。マッチしない場合はnilが返される。 matchDataはマッチした各サブマッチ(またはサブパターン)の内容を取り出すことができるので、次の例を見てほしい。

b1=/[A-Za-z]+,[A-Za-z]+,Mrs?\. /.match("Jack,Wang,Mrs., nice person")
puts b1[0] #-> Jack,Wang,Mrs

b2=/(([A-Za-z]+),([A-Za-z]+)),Mrs?\. /.match("Jack,Wang,Mrs., nice person:)
puts b2[0] #-> Jack,Wang,Mrs
puts b2[1] #-> Jack,Wang
puts b2[2] #-> Jack
puts b2[3] #-> Wang



m[0]はマッチする主式にマッチする文字列を返すので、以下は同等です: m[n]==m.captures[n].

また、Ruby は $1, $2 などの数字で名付けられたグローバル変数を自動的に埋めてくれます。$1 には正規表現の最初の括弧の組にあるサブパターンにマッチする文字列が、左から順に格納されます。外側から内側へ、左から右の順にマッチすることがわかる。

貪欲な量化子と非貪欲な量化子

量詞の*(0個以上)と+(1個以上)は貪欲で、できるだけ多くの文字にマッチします。

以下はそのコードです。1文字以上の文字に感嘆符が続きます。

teststr="abcd!efg!"
match=/. +! /.match(teststr)
puts match[0] #-> abcd!efg!

limitmatch=/. +?! /.match(teststr)
puts limitmatch[0] #-> abcd!



アンカー

アンカーとは、マッチングを継続するために満たさなければならないある条件のことです。

  • 行ヘッダー
  • $ 行末
  • 평평평
  • ⑯文字列の末尾
  • 평평평평
  • \単一単語境界
c=/\b\w+\b/.match("! !Stephen**")

puts c[0] #-> Stephen



Foresightアサーション

前向きなアサーションは、次に何が指定されるかを知りたがっていることを示しますが、一致しません。

肯定的な前向きアサーション (? =)
ドットで終わる数字の列にマッチさせたいが、ドットはパターンマッチの一部にはしたくないとします。

teststr="123 456 789. 012"
m=/\d+(? =\.) /.match(teststr)
puts m[0] #-> 789


否定的な先見性の主張(!?)
上記の例で、 /d+(? = \.) / を /d+(?!!) / と読み替えた場合、 puts m[0] の出力は 123 と表示されます。

修飾語

モディファイアは正規表現の末尾のフォワードスラッシュの後に位置する

1.i 正規表現を大文字小文字を区別しないようにする
例えば、/abc/i は Abc、abc、ABC などにマッチすることができます。

2.mでは、正規表現で任意の文字にマッチング可能 通常、ドット付きワイルドカードではマッチしない改行も含みます。
文字列と正規表現の相互変換

文字列を正規表現に補間する

teststr="a.c"
re=/#{Regexp.escape(teststr)}/
puts re.match("a.c")[0] #-> a.c
test=re.match("abc")
puts test[0] #-> Nil


正規表現を文字列に変換する

puts /abc/.inspect #-> /abc/


正規表現の一般的な使用方法。

  • if や while などに使用します。
  • gsub、grep などに使用します。
  • find_all、scan などに使用します。

例えば、puts "test 1 2 and test 3 4".scan(/d/) は ["1","2","3","4"] と出力されます。