LoginSignup
5
3

More than 3 years have passed since last update.

`String.prototype.split`で区切り文字を複数使いたい場合の書き方

Last updated at Posted at 2021-04-28

以前書いた内容の抜粋だが、本題と離れた話かつ、どう考えても検索に引っかからないので仕切り直し。さらに動作原理について可能な限り詳しく書く。

The quick brown fox jumps over the lazy dog.という文字列をfoxもしくはdogのどちらかでsplitさせて、なおかつ両方ともsplitの内容として残したい場合、正規表現はこう書く。

split.js
"The quick brown fox jumps over the lazy dog.".split(/(fox|dog)/)

しかしこれでは、foxdogの代わりに長い正規表現になった場合区切りが見つかりづらくなる。明示的に2つの正規表現が区切れていることを示すにはどうすればよいのだろうか。

車輪の再発明

まず考えたこととしては、foxdogを正規表現で並立させることである。正規表現で区切り文字を残すには表現を括弧で囲めばいい。これを素直に書けば以下の様になる。
(fox)|(dog)
しかし、これで検索すると以下の様な結果が返ってくる。

(fox)|(dog)でsplitした結果
Array ["The quick brown ", "fox", undefined, " jumps over the lazy ", undefined, "dog", "."]

なに、Undefindedだと? と筆者は最初たじろいでしまった。しかし種が分かればそう慌てるものでもない。
要はsplitでは両方の要素を検索するわけだ。最初のfoxが引っかかった時についでにdogも調べられ、見つからないからundefinedとなってしまうのだ。これはdogとマッチした際にも発生する。

では、((fox)|(dog))とした場合はどうなるのか。まず結果を想像してほしい。きっと実際のものとは違うものになるはずだ。

((fox)|(dog))splitした結果
((fox)|(dog))でsplitした結果
Array ["The quick brown ", "fox", "fox", undefined, " jumps over the lazy ", "dog", undefined, "dog", "."]

なんと大きな括弧のマッチング結果→個別の括弧のマッチング結果という分け方になってしまった!


あなたの考えと合っていましたか? 大当たり? そいつは良かった。

非キャプチャリング括弧

「やっぱ正規表現は難しいわ…」と、思わず弱音を吐きそうになるが、実は正規表現には面白い機能がある。それが「非キャプチャリング括弧」だ。
この機能は、括弧内に?:と書くことで発動し、括弧の内容に「マッチしますが、マッチした内容は記憶しません」。今回の場合どんな意味があるかというと、具体例を見ていただこう。

(?:fox)|(?:dog)でsplitした結果
Array ["The quick brown ", " jumps over the lazy ", "."]

これは、区切り文字をfox|dogと指定した場合と同じだ。ということは、最初に示した例と同様の書き方をしてみると…

((?:fox)|(?:dog))でsplitした結果
Array ["The quick brown ", "fox", " jumps over the lazy ", "dog", "."]

つまり、最初の目的を達成する書き方は((?:fox)|(?:dog))である。無駄に遠回りをしているが、これでsplitの区切りが分かりやすくなった! …はずだ。

5
3
3

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
5
3