第15回 パターンマッチと正規表現

 2008-09-03
今回は正規表現についてです。

存在自体知らない人なんかもいるんじゃないかな?

※ 9月4日 いろいろ追記


正規表現については、
[RGSS リファレンス] - [付録] - [正規表現]
[RGSS リファレンス] - [標準ライブラリ] - [組み込みクラス] - [Object] -[Regexp]

に詳しく書いてあります。

正規表現とは、文字列のパターンを指定するための表記方法です。
このパターンは、正規表現記号 (メタ文字)を使用して記述します。
比較した結果が指定されたパターンの文字列ならば、「マッチする」
違うならば「マッチしない」と言います。

パターンとは、例えば「"数字 + 数字 + 何か文字"の組み合わせ」といったものです。
このパターンに合うものが"123"や"00あ"などです。
そして、後述しますが、更にこの組み合わせが含まれる文字列かを
判断するのが"パターンマッチ"です。
つまり、"12345"や"あと10分休憩"などにもマッチします。
これらのどこにマッチしたかというと、"123"や"10分"という部分です。

さて、ヘルプに使い方は載っていますが、どんなときに使用するのでしょう?
これは、ある文字列がどのようなものか知りたい場合などに用います。

foo = "cde"
bar = "abcde"
baz = "bcdef"
これらの変数には、それぞれ異なった値が格納されています。
もちろん、単純に比較すれば、すべて false が返ってくるでしょう。
p foo == bar    # => false
p foo == baz    # => false
このような単純な比較ではなく、ある文字が含まれているかどうかを
判別するのが"パターンマッチ"です。

この3つの変数には、"cde"という文字が含まれています。
次のように記述することで、すべて true が返ります。
p /#{foo}/ === bar    # => true
p /#{foo}/ === baz    # => true


パターンマッチとは、左の正規表現(パターン)が右の文字列に含まれるかを判断します。
# 先頭から123
re = /^123/
p re === "12345" # => true
p re === "01234" # => false

# 自○という漢字
re = /自[一-龠]/
p re === "自分" # => true
p re === "大自然" # => true
p re === "自ら" # => false


ヘルプを呼んでもらえばわかると思いますが、少しだけ補足してみます。
◆ ^と\Aの違い
p "12\n345\n6789\n0".scan(/^\d+/) # => ["12", "345", "6789", "0"]
p "12\n345\n6789\n0".scan(/\A\d+/) # => ["12"]
^ は、行の先頭にマッチします。
\A は、文字列の先頭にマッチします。

◆ $と\Zと\zの違い
str = "123\n456\n789\n0\n"
p str.scan(/\d+$/) # => ["123", "456", "789", "0"]
p str.scan(/\d+\Z/) # => ["0"]
p str.scan(/\d+\z/) # => []
$ は、行の末尾にマッチします。
\Z は、文字列の末尾にマッチします。もし改行だったなら、その直前の位置にマッチします。
\z は、純粋に文字列の末尾にマッチします。

◆ \bと\Bって何?
p "000".gsub(/\b/, "!") # => "!000!"
p "000".gsub(/\B/, "|") # => "0|0|0"
\b は、文字列の前後にマッチします。
\B は、すべての文字の間にマッチします。

◆ 最短一致って何?
/<.*>/ =~ "<123>456<789>"
p $& # => "<123>456<789>"
/<.*?>/ =~ "<123>456<789>"
p $& # => "<123>"
最長一致の場合は、その名の通り最も長く一致しようとします。
上の例では、一見、<123>にマッチするかのように思えますが、最も長く一致しようとするため
最初の">"は、"."つまり任意の一文字と判断されてしまいます。
そのため、最後の">"までがマッチします。
最短一致の場合は、最短で一致しようとするため
最初の">"を任意の一文字に数えず、">"と判断するわけです。


では最後にCACAOさんからの問題です。
この問題が解ければ、正規表現は大丈夫ですね?

問1.次の出力される文字を答えなさい。
/^.*(\d\d)?/ =~ "a8ef43lj123a98e"
p $1
A.nil

問2.3桁区切りになるように、変数 re に適切な値を入れなさい。
re = //
"12345678".gsub(re, ",") # => "12,345,678"
A./(?=[1-9]\d\d(\d{3})*$)/

問3.整数のみにマッチするように、変数 re に適切な値を入れなさい。
re = //
str = <<EOS
0
-56
0.3
15a6
109
0123
EOS
str.scan(re) # => ["0", "-56", "109"]
A./^(?:-?[1-9]\d*|0)$/

※ Ruby/RGSS2以外の言語を知っている方は注意してください。
  多くの多言語とは違い、正規表現を左に記述します。
※ この講座では、マッチしたかどうかがわかりやすいように === を使用しています。
  しかし、一般的な =~ も使用できます。その場合、結果を 0 / nil で返します。
※ 答えは、ドラッグして表示させてください。

◆ 今回のポイント
・ 正規表現とは、 /.../ の部分である。
・ パターンマッチとは、=~ や === を用いて比較することである。
・ 判断基準は、「パターンと同じ文字列」ではなく、「パターンを含む文字列」である。
・ 正規表現は、左に記述する。
・ マッチした文字列は、組み込み変数に格納される。
・ 文字クラス指定( [ ] )は、指定された文字のどれか1文字にマッチする。
・ 選択( | )は、最も優先順位が低いため、グループ化して使用する。
コメント




 

 ※ コメント内にURLを含めるには、バッククォート(`)をURLの直前に付け加えてください。


管理人のみ閲覧許可 [?]

トラックバック
トラックバックURL:
http://cacaosoft.blog42.fc2.com/tb.php/97-f1c2af6e
≪ トップページへこのページの先頭へ  ≫
カレンダー
09 << 2017/10 >> 11
1 2 3 4 5 6 7
8 9 10 11 12 13 14
15 16 17 18 19 20 21
22 23 24 25 26 27 28
29 30 31 - - - -

カテゴリー
最近の記事
最近のコメント
タグクラウド

リンク