Summary. プログラミングに興味が無い人でも知っておくと役に立つ(かもしれない)正規表現について簡単に紹介してみます。メインテーマは「JavaScriptで正規表現をどう使うか」ですが、他にもテキストエディタでの検索や置換に利用できるので結構お得です。

正規表現について

正規表現(regular expression)は、フォームの入力内容やテキストファイルなどテキスト形式のデータ(文字列といいます)を処理するときに役に立つ機能です。

簡単な例を1つ。

たとえばいま、"メモ.txt" というテキストファイルをワープロソフト(or テキストエディタ)で開いているとします。このファイルの中で "猫" という単語がどこに出てくるか探したいときは、よく知られているようにワープロソフトの検索機能を使えばよいです:


しかし、もしかしたら漢字で "猫" と書く以外にも "ねこ" や "ネコ" という表記も混ざっているかもしれません。
そんなときはいわゆるOR検索が必要になります。もし正規表現を検索に使えるソフトであれば次のように検索できます[1]


というか実際はそれどころの騒ぎではなく、正規表現を使えば猫以外のどんな動物にまみれていても一度に検索してしまうことができます:


まあ、今の例だと「単に "まみれ" で検索すればいいじゃん」というツッコミが入るところではあるんですがw
ともあれ、正規表現を使うと単純な検索よりも自由度の高いパターンマッチングを行うことができます。

上のスクリーンショットで (\S+) という部分が何を意味するのか、ここでは解説しません[2]。それはむしろ正規表現関係のサイトを見てもらったほうがよいでしょう。少しだけ紹介しておきます:

正規表現サンプル集
http://hodade.adam.ne.jp/seiki/

Regular Expression(Riue ちゃんの正規表現講座)
http://www.sixnine.net/regexp/index.html

他にどんな検索が可能か、簡単なものを説明抜きに書いてみます。正規表現の大まかなイメージが掴めるといいのですが・・・

ちょw+ いわゆる草(w)が1個以上生えている場合にマッチします。
例: ちょw, ちょww, ちょwww, ...
ちょw* 上と似ていますが、草が0個でもマッチします。
例: ちょ, ちょw, ちょww, ...
. 任意の1文字(半角空白なども含む)にマッチします [3]
例: a, あ, #, ♂, ...
作者は.+タグ "作者は" で始まって "タグ" で終わる部分にマッチします。
例: 作者は病気タグ, ...
[A-Z0-9]+ アルファベット大文字と数字だけからなる部分にマッチします。
例: XYZ, A2K, AD2010, ...
[0-9]+月[0-9]+日 日付(っぽいもの)にマッチします。
例: 3月10日, 12月31日, ...
-[1-9][0-9]* 負の整数にマッチします。
例: -9, -25, -1024, ...
(.+)は\1 "餅は餅屋" のような文にマッチします。
例: そばはそば屋, 母は母屋, ...

JavaScriptで正規表現を使う

正規表現は様々なプログラミング言語で利用可能です。JavaScriptもその1つで、非常に簡単な文でパターンマッチングを行うことができます。
text = "その剣なら 7125G で買い取るぜ?";
gold = text.match(/[0-9]+G/);
上のコードを実行すると gold に "7125G" という文字列が代入されます。このように、match メソッドを使うとテキストデータから必要な部分を切り出せます。なお、マッチする部分が複数あった場合は一番左にあるものが優先されます。

マッチする部分をすべて取り出すにはgオプションを付けてやります:
text = "テレビも無エ ラジオも無エ 自動車もそれほど走って無エ";
list = text.match(/...も/g);
上のように書くと list には {"テレビも", "ラジオも", "自動車も"} という配列が代入されます。似たようなことは split メソッドでもできますが、後述のグループ化と組み合わせることでより高度な処理が行えます。

match の他にもう1つ、replace という便利なメソッドもあります。これは正規表現にマッチした部分を他のものに置換する機能を持っています。
text = "うはwWWwwWwWwwWWwwWWwwwW";
window.alert( text.replace(/[WwWw]/g, "") );
上の例では replace によって草が全部刈り取られます(この書き方だと関係ない w まで巻き添えを食って消えてしまいますが・・・)。他にも色々な機能がありますが、どんなものが用意されているかはJavaScript関係のサイトをご覧ください。自分は とほほのJavaScriptリファレンス さんの「文字列(String)」の項をよく見ます。

グループ化

正規表現における丸括弧は通常の文字とは違う特別な意味を持っています。その1つは、数学などと同じように複数の文字を一括りにする機能です:
text = "ありゃりゃりゃりゃ・・・";
text.match(/(りゃ)+/);
window.alert( RegExp.lastMatch );
想像に難くないでしょうが、上の例では "りゃりゃりゃりゃ" の部分だけが得られます。ここで注目すべきは match メソッドの返り値をそのまま使ってはいない という点です。実はこれ、丸括弧が持つもう1つの大事な機能(キャプチャと呼ばれる)と関係しています。

で、その「もう1つの機能」を使ってみたのが次の例です:
text = "レンはうちの猫";
text.match( /(.+)は(.+)の(.+)/ );
window.alert( RegExp.lastMatch );
window.alert( RegExp.$1 );
window.alert( RegExp.$2 );
window.alert( RegExp.$3 );
このコードを実行すると計4回ダイアログが出てきて、それぞれ "レンはうちの猫", "レン", "うち", "猫" という文字列を表示するはずです。要するに、RegExp.$1 ~ RegExp.$3 たちを使うと 括弧で括った部分だけを取り出すことができる わけです。

これを応用すると
window.alert( "残念それは別の" + RegExp.$3 + "だ。");
window.alert( "本物の" + RegExp.$1 + "は俺の隣にいるよ。" );
というふざけた凝ったメッセージを表示することもできます。こんなふうにグループ化を含む正規表現を渡した場合、match メソッドの返り値は上の RegExp.lastMatch ~ RegExp.$3 を要素とする配列になります。


グループ化はとても便利な機能であり、それと同時に記述が煩雑になりやすい部位でもあるのでもう1つだけ例を挙げておきます:
ratio = new Object();
ratio["m"] = 1000;
ratio["cm"] = 10;
ratio["mm"] = 1;

text = "2m 10cm, 140mm, 50cm 5mm";
mm = 0;

while( text.match(/([0-9]+)([cm]?m)/) ){
  mm += parseInt(RegExp.$1) * ratio[RegExp.$2];
  text = RegExp.rightContext;
}

window.alert("合計" + mm + "ミリメートル");
同じことを正規表現無しで行おうとしたら、結構面倒なコードを書かなければいけません。それがたったの数行で(しかも簡単に)実現できます。上手く使いこなせばいろんなプログラムを作れそうな気がしませんか?[4]

余談

次の正規表現は実際にcalc_damage.jsで使っているものです:
var CMD_PAT = /^([\w\+\-\*\[\]@]+)(\([\d\-,]+\))?/;
var ARG_PAT = /(\d+\-\d+|\d+)/g;
我ながら読みづらいとは思いますが、実際は大したことはしていません(だからよいってもんでもないですが)。この程度ならマシなほうだと。こういうのをネットで探すと、なかなか面白いものが見つかったりします。






[1]
今回はK2Editor(http://k2top.jpn.org/index.php?K2Editor)を使用しました。

[2]
ただし、括弧が普通の意味の括弧でないことだけは注意しておく。通常の括弧にマッチさせたいときは \( とか \) のように円マークを付けて書く。

[3]
改行文字以外のどんな文字でもマッチするため、気を付けないと予想外の結果を引き起こしかねない。目的に応じて \w \S と使い分けるとよい。

[4]
もちろん正規表現も万能ではない。それは計算理論的にも実証されている・・・らしい(ぉ
最終更新:2021年12月31日 23:01