8.正規表現
1.正規表現とは
正規表現とは、文字列のパターンを指定するための表記方法です。
このパターンは、正規表現記号 (メタ文字)を使用して記述します。
比較した結果が指定されたパターンの文字列ならば、「マッチする」
違うならば「マッチしない」と言います。
正規表現については、ヘルプの次の項目に詳しく書いてあります。
[RGSS リファレンス] - [付録] - [正規表現]
[RGSS リファレンス] - [標準ライブラリ] - [組み込みクラス] - [Object] - [Regexp]
正規表現を知らない人には暗号に見えてしまうかもしれませんが、
検索したい文字を1字1字メタ文字に置き換えただけです。
たとえば、3桁の数字を検索する場合は、/\d\d\d/ となります。
簡単ですね。\dが数字を表すメタ文字なので、「数字 + 数字 + 数字」と並べただけです。
また、正規表現はパターンの文字が含まれるかを判定するものですから、
「数字 + 数字 + 文字」:/\d\d./ だと、"12345"や"あと10分休憩"などにもマッチします。
これらのどこにマッチしたかというと、"123"や"10分"という部分です。
このパターンは、正規表現記号 (メタ文字)を使用して記述します。
比較した結果が指定されたパターンの文字列ならば、「マッチする」
違うならば「マッチしない」と言います。
正規表現については、ヘルプの次の項目に詳しく書いてあります。
[RGSS リファレンス] - [付録] - [正規表現]
[RGSS リファレンス] - [標準ライブラリ] - [組み込みクラス] - [Object] - [Regexp]
正規表現を知らない人には暗号に見えてしまうかもしれませんが、
検索したい文字を1字1字メタ文字に置き換えただけです。
たとえば、3桁の数字を検索する場合は、/\d\d\d/ となります。
簡単ですね。\dが数字を表すメタ文字なので、「数字 + 数字 + 数字」と並べただけです。
また、正規表現はパターンの文字が含まれるかを判定するものですから、
「数字 + 数字 + 文字」:/\d\d./ だと、"12345"や"あと10分休憩"などにもマッチします。
これらのどこにマッチしたかというと、"123"や"10分"という部分です。
2.どんなときに使うの?
ある文字列がどのようなものか知りたい場合などに用います。
もちろん、単純に比較すれば、すべてfalseが返ってくるでしょう。
この3つの変数には、"cde"という文字が含まれています。
次のように記述することで、すべてtrueが返ります。
具体的には、ある数値を3桁区切りの文字列にしたい場合や、
データベースのメモ欄を使用するときなんかに使用します。
メモ欄で使用することを想定したサンプルは、こちらにあります。
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
具体的には、ある数値を3桁区切りの文字列にしたい場合や、
データベースのメモ欄を使用するときなんかに使用します。
str = 1234567890.to_s
p str.gsub(/(?!^)(?=(\d{3})*$)(?=\d)/, ",") # => "1,234,567,890"
メモ欄で使用することを想定したサンプルは、こちらにあります。
3.解かり辛いであろう箇所
◆ [] と | の違い
[]内にある1文字にマッチします。今回は、"明" と "日" のどちらかですね。
|で区切った部分で分けます。この場合、"前日" と "後日" のどちらかです。
| は、優先順位が低いので、普通はグループわけをして使用します。
◆ ^と\Aの違い
\Aは、文字列の先頭にマッチします。
◆ $と\Zと\zの違い
\Zは、文字列の末尾にマッチします。もし改行だったなら、その直前の位置にマッチします。
\zは、純粋に文字列の末尾にマッチします。
◆ \bと\Bって何?
例えば、ABC,123 だと文字と記号の境界は、ABC|,|123 の | の位置となります。
\bは、文字と記号の境界にマッチします。
\Bは、文字と記号の非境界にマッチします。
◆ 最短一致って何?
上の例では、一見、<123>にマッチするかのように思えますが、最も長く一致しようとするため
最初の">"は、"."つまり任意の一文字と判断されてしまいます。
そのため、最後の">"までがマッチします。
最短一致の場合は、最短で一致しようとするため
最初の">"を任意の一文字に数えず、">"と判断するわけです。
regexp = /[明日]/ p regexp === "明日" # => true p regexp === "10日" # => true regexp = /前日|後日/ p regexp === "前の日" # => false p regexp === "明後日" # => true[...] が文字、| が文字列にマッチさせたいときに使用します。
[]内にある1文字にマッチします。今回は、"明" と "日" のどちらかですね。
|で区切った部分で分けます。この場合、"前日" と "後日" のどちらかです。
| は、優先順位が低いので、普通はグループわけをして使用します。
◆ ^と\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 "a bc あ".split(/\b/) # => ["a", " ", "bc", " ", "あ"] p "a1$$b2".split(/\B/) # => ["a", "1$", "$b", "2"] p "000".gsub(/\b/, "!") # => "!000!" p "000".gsub(/\B/, "|") # => "0|0|0" p /\b(red)\b/ === "shred redraw" # => false文字(英数字や日本語)の境界で判定を行います。
例えば、ABC,123 だと文字と記号の境界は、ABC|,|123 の | の位置となります。
\bは、文字と記号の境界にマッチします。
\Bは、文字と記号の非境界にマッチします。
◆ 最短一致って何?
/<.*>/ =~ "<123>456<789>" p $& # => "<123>456<789>" /<.*?>/ =~ "<123>456<789>" p $& # => "<123>"最長一致の場合は、その名の通り最も長く一致しようとします。
上の例では、一見、<123>にマッチするかのように思えますが、最も長く一致しようとするため
最初の">"は、"."つまり任意の一文字と判断されてしまいます。
そのため、最後の">"までがマッチします。
最短一致の場合は、最短で一致しようとするため
最初の">"を任意の一文字に数えず、">"と判断するわけです。
4.マッチ文字の取得
マッチした文字は、$&変数に格納されています。
また、グループ化された文字列は、さらに$1,$2,$3... のような変数に格納されます。
$+には、最後にマッチしたグループの値が格納されます。
マッチしなかった文字列の取得も可能です。
$`で、マッチした文字列より前の文字列を
$'で、マッチした文字列より後ろの文字列を取得することができます。
これらの変数は、正規表現を使用するたびに初期化されます。
また、マッチした文字列は、MatchData クラスで管理されます。
そして、そのインスタンスは$~変数に格納されています。
先程の変数をすべて置き換えてみます。
また、グループ化された文字列は、さらに$1,$2,$3... のような変数に格納されます。
$+には、最後にマッチしたグループの値が格納されます。
マッチしなかった文字列の取得も可能です。
$`で、マッチした文字列より前の文字列を
$'で、マッチした文字列より後ろの文字列を取得することができます。
"ABC123!@@".match(/\d+([!])/) p $& # => "123!" p $1 # => "!" p $2 # => nil p $` # => "ABC" p $' # => "@@" p $+ # => "!"$2の値は、2つ目のグループが無かったためnilとなっています。
これらの変数は、正規表現を使用するたびに初期化されます。
また、マッチした文字列は、MatchData クラスで管理されます。
そして、そのインスタンスは$~変数に格納されています。
先程の変数をすべて置き換えてみます。
"ABC123!@@".match(/\d+([!])/) p $~[0] # => "123!" p $~[1] # => "!" p $~[2] # => nil p $~.pre_match # => "ABC" p $~.post_match # => "@@" p $~[-1] # => "!" p $~.to_a # => ["123!", "!"]
5.今回のポイント
・正規表現とは、 /.../ の部分である。
・パターンマッチとは、=~ や === を用いて比較することである。
・判断基準は、「パターンと同じ文字列」ではなく、「パターンを含む文字列」である。
・正規表現は、左に記述する。
・マッチした文字列は、組み込み変数に格納される。
・文字クラス指定( [ ] )は、指定された文字のどれか1文字にマッチする。
・選択( | )は、最も優先順位が低いため、グループ化して使用する。
・パターンマッチとは、=~ や === を用いて比較することである。
・判断基準は、「パターンと同じ文字列」ではなく、「パターンを含む文字列」である。
・正規表現は、左に記述する。
・マッチした文字列は、組み込み変数に格納される。
・文字クラス指定( [ ] )は、指定された文字のどれか1文字にマッチする。
・選択( | )は、最も優先順位が低いため、グループ化して使用する。