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

正規表現については、ヘルプの次の項目に詳しく書いてあります。
 [RGSS リファレンス] - [付録] - [正規表現]
 [RGSS リファレンス] - [標準ライブラリ] - [組み込みクラス] - [Object] - [Regexp]


正規表現を知らない人には暗号に見えてしまうかもしれませんが、
検索したい文字を1字1字メタ文字に置き換えただけです。
たとえば、3桁の数字を検索する場合は、/\d\d\d/ となります。
簡単ですね。\dが数字を表すメタ文字なので、「数字 + 数字 + 数字」と並べただけです。

また、正規表現はパターンの文字が含まれるかを判定するものですから、
「数字 + 数字 + 文字」:/\d\d./ だと、"12345"や"あと10分休憩"などにもマッチします。
これらのどこにマッチしたかというと、"123"や"10分"という部分です。
2.どんなときに使うの?
ある文字列がどのようなものか知りたい場合などに用います。
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.解かり辛いであろう箇所
◆ [] と | の違い
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... のような変数に格納されます。
$+には、最後にマッチしたグループの値が格納されます。
マッチしなかった文字列の取得も可能です。
$`で、マッチした文字列より前の文字列を
$'で、マッチした文字列より後ろの文字列を取得することができます。
"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文字にマッチする。
・選択( | )は、最も優先順位が低いため、グループ化して使用する。