以前書いた内容の抜粋だが、本題と離れた話かつ、どう考えても検索に引っかからないので仕切り直し。さらに動作原理について可能な限り詳しく書く。
The quick brown fox jumps over the lazy dog.
という文字列をfox
もしくはdog
のどちらかでsplit
させて、なおかつ両方ともsplit
の内容として残したい場合、正規表現はこう書く。
"The quick brown fox jumps over the lazy dog.".split(/(fox|dog)/)
しかしこれでは、fox
やdog
の代わりに長い正規表現になった場合区切りが見つかりづらくなる。明示的に2つの正規表現が区切れていることを示すにはどうすればよいのだろうか。
#車輪の再発明
まず考えたこととしては、fox
とdog
を正規表現で並立させることである。正規表現で区切り文字を残すには表現を括弧で囲めばいい。これを素直に書けば以下の様になる。
(fox)|(dog)
しかし、これで検索すると以下の様な結果が返ってくる。
Array ["The quick brown ", "fox", undefined, " jumps over the lazy ", undefined, "dog", "."]
なに、Undefinded
だと? と筆者は最初たじろいでしまった。しかし種が分かればそう慌てるものでもない。
要はsplit
では両方の要素を検索するわけだ。最初のfox
が引っかかった時についでにdog
も調べられ、見つからないからundefined
となってしまうのだ。これはdog
とマッチした際にも発生する。
では、((fox)|(dog))
とした場合はどうなるのか。まず結果を想像してほしい。きっと実際のものとは違うものになるはずだ。
`((fox)|(dog))`で`split`した結果
Array ["The quick brown ", "fox", "fox", undefined, " jumps over the lazy ", "dog", undefined, "dog", "."]
なんと大きな括弧のマッチング結果→個別の括弧のマッチング結果という分け方になってしまった!
#非キャプチャリング括弧
「やっぱ正規表現は難しいわ…」と、思わず弱音を吐きそうになるが、実は正規表現には面白い機能がある。それが「非キャプチャリング括弧」だ。
この機能は、括弧内に?:
と書くことで発動し、括弧の内容に「マッチしますが、マッチした内容は記憶しません」。今回の場合どんな意味があるかというと、具体例を見ていただこう。
Array ["The quick brown ", " jumps over the lazy ", "."]
これは、区切り文字をfox|dog
と指定した場合と同じだ。ということは、最初に示した例と同様の書き方をしてみると…
Array ["The quick brown ", "fox", " jumps over the lazy ", "dog", "."]
つまり、最初の目的を達成する書き方は((?:fox)|(?:dog))
である。無駄に遠回りをしているが、これでsplit
の区切りが分かりやすくなった! …はずだ。