Caution

お使いのブラウザはJavaScriptが実行できない状態になっております。
当サイトはWebプログラミングの情報サイトの為、
JavaScriptが実行できない環境では正しいコンテンツが提供出来ません。
JavaScriptが実行可能な状態でご閲覧頂くようお願い申し上げます。

  1. トップページ
  2. JavaScript応用編 - 文字を検索または特定できる正規表現とは

文字を検索または特定できる正規表現とは

(´-`).。oO(AGA(ハゲ)のお薬を数年間飲み続けたところ...)

(´-`).。oO(ちょっと髪の毛が生えてきました...)

ヽ(*>∇<)ノ♪

というわけでみなさまどうも。科学の力は偉大でございますね。

さて、続きまして『正規表現』(せいきひょうげん)について色々やっていきましょう。

『正規表現』とは文字列を検索(パターンを表現)することに特化した表記方法の一つです。

『正規表現』を使用すると文字列の中から任意のパターンにマッチする文字列を特定し、そこに処理を加えたりと様々なことができるようになります。

そんでもってほぼ全てのプログラム言語に『正規表現』の機能が搭載されていたりしますので「『正規表現』ってなにそれ美味しいの?」って方は是非覚えてしまって下さい。構築できる処理の幅が爆発的に広がるのでスキルアップ間違いなしでございます。

んで早速ですがちょっと注意点です。プログラム言語によって『正規表現』の記述方法が結構違います

なのでJavaScriptの『正規表現』を他の言語とかにそのままコピペして実行させようとしても動かない場合があります。これ、忘れないようにして下さい。いずれ苦労することになると思います。

そんでもって『正規表現』をガチで解説するとなると薄い本が一冊書けるくらいの規模になりますので今回はJavaScriptの『正規表現』が軽く書けるようになるくらいまでの解説とさせて頂きますね。正規表現超まとめとかはいつの日か執筆します、多分。

JavaScriptでの『正規表現』は『Perl』(5系)の『正規表現』とほぼ同じです。

ですので『perl』の経験者の方はほぼ同じ『正規表現』を使用することができ、『正規表現』だけでみると『perl』とJavaScriptの親和性はかなり高かったりします。

ではやっていきましょう。

まずJavaScriptで文字列の痴漢置換を行える『String.replace()』というのがありますのでこちらを紹介しておきます。

使い方は簡単で、第1引数に置換する文字列、第2引数に置換したい文字列を記述すればOKです。元となる文字列に『.replace()』を付ける形になりますのでそこだけご注意下さい。以下がサンプルです。

"あいうえお".replace("あいう", "かきく"); // 文字列『かきくえお』が返って来ます。

"あいうえお".replace("あいう", ""); // 一致した文字列を削除したい場合は第2引数に空文字列を指定します。この場合は文字列『えお』が返って来ます。

var x = "初音ミク";
x.replace("初音ミク", "Miku Hatsune"); // 変数に代入された文字列でも『.replace()』をつけちゃってOKです。

"あいうえお".replace("かきくけこ", "さしすせそ"); // 一致しなかった場合はそのままの文字列が返って来ます。この場合は文字列『あいうえお』が返って来ます。

さて、この『String.replace()』は『正規表現』を使用した置換も行うことができますのでこちらを使って色々と試してみましょう。

まず『正規表現』の記述方法ですが、『/』で文字とか記号とかを囲んであげればOKです。こんな感じですね。

var x = /abc/; // 正規表現『abc』を変数『x』に代入します。

通常の文字列だと『"』か『'』で囲いますが、『正規表現』の場合は『/』です。『//』としてしまうとコメントになっちゃうので注意です。

では続いて普通の英数字とか日本語を使った『正規表現』で置換をしてみましょう。以下のような感じになります。

"Naked Snake".replace(/Naked Snake/, "BIG BOSS"); // 文字列『BIG BOSS』が返って来ます。
"ワンパンマン".replace(/ワンパンマン/, "サイタマ"); // 文字列『サイタマ』が返って来ます。
"ぼくはわんこが好きです。".replace(/わ/, "う"); // 文字列『ぼくはうんこが好きです。』が返って来ます。

ただ文字列がそのまま置換されているのが確認できるかと思います。

こんな感じで、普通の英数字とか日本語を使った『正規表現』での特定は『"』か『'』を使用した通常の文字列で特定を行った場合と特に変化はありません。

しかし、『正規表現』には通常の文字列にはない機能が備わっていますのでちょっとそいつを使ってみましょう。というわけで紹介します。『.』です。『正規表現』では『.』で「なんでも良い一文字」が表現できます。というわけで以下のサンプルを見て下さい。

"a".replace(/./, "x");

置換対象に『/./』と記述されていますね。これを実行させるとこうなります。

"x"

「なんでも良い一文字」なので文字列『a』が『x』に置換されました。

そして英数字と『.』を組み合わせると以下のような置換処理が構築できます。

"abc".replace(/a.c/, "xxx"); // 文字列『xxx』が返って来ます。
"acc".replace(/a.c/, "xxx"); // 文字列『xxx』が返って来ます。
"adc".replace(/a.c/, "xxx"); // 文字列『xxx』が返って来ます。
"aあc".replace(/a.c/, "xxx"); // 文字列『xxx』が返って来ます。

"aaaaあいうcccc".replace(/a...c/, "xxx"); // 一部分だけ変更したい場合はこんな感じです。文字列『aaaxxxccc』が返って来ます。

上記のサンプルを見るとひとつの『正規表現』で色々なパターンが特定できていますね。これが『正規表現』の便利な機能になります。

そして『.』のような特殊な機能を持つ文字をメタ文字(特殊文字)と言います。このメタ文字を上手く扱うことで様々な文字列パターンを特定することができるようになります。

尚、メタ文字扱いになるのは記号だけですのでほぼ全ての英数字と日本語は普通の文字として扱われます。これについては「メタ文字扱いされるのは記号のみ」という漠然とした感じで覚えちゃっても問題ないかと思います。

『/』で囲まれた正規表現的なオブジェクト(データ)を『正規表現リテラル』と呼ばれたり呼ばれなかったりします。

尚、会話では単純に『正規表現』と呼ばれる事が多く、しかも参考書によって微妙に呼び方が違ったりする場合があるのでご注意下さい。

JavaScriptでの『正規表現』の『.』は改行文字の特定はしてくれません。

"\n".replace(/./, "a"); // これは置換されません。

ハマりやすいポイントなのでご注意下さい。

ちなみに『正規表現』のメタ文字をエスケープさせる(普通の文字として扱わせる)には『\』(バックスラッシュ)を手前に添えてあげればOKです。以下のような感じですね。

※ WindowsOSの型は『バックスラッシュ』が『円マーク』になっちゃってるかもしれませんのでご注意です。詳しくはこちらへどうぞ。

".".replace(/\./, "a"); // 文字列『.』を文字列『a』に置換します。
"a?c".replace(/a\?c/, "xyz"); // 文字列『a?c』を文字列『xyz』に置換します。
"[]".replace(/\[\]/, "a"); // 文字列『[]』を文字列『a』に置換します。

『\』を特定したい場合は『\\』と記述して下さい。ちょっと注意点ですが、『"』や『'』で囲った通常の文字列の『\』もエスケープする必要がありますので気をつけて下さい。

"\\".replace(/\\/, "x"); // 文字列『x』が返って来ます。

そして『\』にはメタ文字をエスケープするだけでなく、いくつか別の使い方がありますので紹介します。

まず『"』や『'』を使用した普通の文字列と同じく、改行を表す『\n』やタブ文字を表す『\t』等のエスケープシーケンスも問題なく使用することができます。

"abc\nabc".replace(/\n/, ""); // 改行が削除されて文字列『abcabc』が返って来ます。
"abc\tabc".replace(/\t/, ""); // タブ文字が削除されて文字列『abcabc』が返って来ます。

そして『正規表現』には『文字クラス』という文字の集合を表現できる表記法みたいなのが用意されており、それの略記法で『\』が使用されたりしますね。

主に使用される『文字クラスの略記法』は、半角スペースを表現する『\s』、半角スペース以外を表現する『\S』、半角の数値を表現する『\d』、半角の数値以外を表現する『\D』、なんかになります。使い方はこんな感じです。

" ".replace(/\s/, "x"); // 文字列『x』が返って来ます。
"a".replace(/\S/, "x"); // 文字列『x』が返って来ます。
"0".replace(/\d/, "x"); // 文字列『x』が返って来ます。
"100".replace(/\d\d\d/, "x"); // 文字列『x』が返って来ます。
"a".replace(/\D/, "x"); // 文字列『x』が返って来ます。
"abc".replace(/\D\D\D/, "x"); // 文字列『x』が返って来ます。

他にも『文字クラスの略記法』が用意されてたりします。ただ、動作がはっきりしていなかったりブラウザよって違いが出たりする場合がありますので使用の際は注意するようにして下さい。

さて、では改めまして『.』以外の他のメタ文字をバシバシ紹介していきたいと思います。

まず同じ文字が繰り返されたときの特定に使用される『*』と『+』と『?』です。

『*』は直前の文字が存在しないか、もしくは一文字以上繰り返されていた場合に特定、『+』は直前の文字が一文字以上繰り返されていた場合に特定、『?』は直前の文字が存在しないか、一文字だった場合に特定してくれます。

ちょっと慣れないとややこしいので細かく見ていきましょう。

『*』は直前の文字が存在しないか、もしくは一文字以上繰り返されていた場合に特定なので以下のパターン全てを特定してくれます。

// 以下のサンプルの繰り返しの対象となる文字は『Y』です。
"WR".replace(/WRY*/, "オラオラオラオラ"); // 文字列『オラオラオラオラ』が返って来ます。
"WRY".replace(/WRY*/, "オラオラオラオラ"); // 文字列『オラオラオラオラ』が返って来ます。
"WRYY".replace(/WRY*/, "オラオラオラオラ"); // 文字列『オラオラオラオラ』が返って来ます。
"WRYYY".replace(/WRY*/, "オラオラオラオラ"); // 文字列『オラオラオラオラ』が返って来ます。
"WRYYYY".replace(/WRY*/, "オラオラオラオラ"); // 文字列『オラオラオラオラ』が返って来ます。

『+』は直前の文字が一文字以上繰り返されていた場合に特定なので以下のパターンが特定されます。

// 以下のサンプルの繰り返しの対象となる文字は『Y』です。
"WRY".replace(/WRY+/, "オラオラオラオラ"); // 文字列『オラオラオラオラ』が返って来ます。
"WRYY".replace(/WRY+/, "オラオラオラオラ"); // 文字列『オラオラオラオラ』が返って来ます。
"WRYYY".replace(/WRY+/, "オラオラオラオラ"); // 文字列『オラオラオラオラ』が返って来ます。
"WRYYYY".replace(/WRY+/, "オラオラオラオラ"); // 文字列『オラオラオラオラ』が返って来ます。

"貴様!?ディオ!オララララララララララ...".replace(/オラ+/, "あわわわわわわ"); // 文字列『貴様!?ディオ!あわわわわわわ...』が返って来ます。

『+』は以下のパターンだと特定されません。

"WR".replace(/WRY+/, "オラオラオラオラ"); // これは特定されません。

『?』は直前の文字が存在しないか、一文字だった場合に特定なので以下のパターンが特定されます。

// 以下のサンプルの繰り返しの対象となる文字は『Y』です。
"WR".replace(/WRY?/, "オラオラオラオラ"); // 文字列『オラオラオラオラ』が返って来ます。
"WRY".replace(/WRY?/, "オラオラオラオラ"); // 文字列『オラオラオラオラ』が返って来ます。

そして、『*』と『?』の使用に関しての注意点なのですが、『*』と『?』は直前の文字が0回の繰り返しだった場合にも特定されちゃいます。ちょっと以下のパターンを見てみましょう。

"WRYYYY".replace(/U*/, "U");

上記の場合、文字列『U』は特定したい文字列『WRYYYY』には含まれていません。なので特定されずに処理が終わるかと思いきやこのような結果になります。

"UWRYYYY"

頭に『U』がくっついちゃいました。

なんでこんな結果になるかというと、「先頭に文字列『U』が0回繰り返されている」と判定されて、そこが置換されてしまったためです。つまり存在しない文字(空文字列)も特定の文字が0回繰り返されているものとして特定されてしまうということになりますね。

"こぉぉぉぉおおお!!".replace(/お*/, "うん"); // 文字列『うんこぉぉぉぉおおお!!』が返って来ます。
"こぉぉぉぉおおお!!".replace(/お?/, "うん"); // 文字列『うんこぉぉぉぉおおお!!』が返って来ます。

これ、結構ハマりやすいポイントなんで忘れないようにして下さい。

イメージとしては『何か一文字』の右隣に『*』または『?』が置かれた場合に先頭の空文字列が特定されてしまうって感じです。

"こぉぉぉぉおおお!!".replace(/あ*/, "うん"); // 文字列『うんこぉぉぉぉおおお!!』が返って来ます。
"こぉぉぉぉおおお!!".replace(/い*/, "うん"); // 文字列『うんこぉぉぉぉおおお!!』が返って来ます。
"こぉぉぉぉおおお!!".replace(/う*/, "うん"); // 文字列『うんこぉぉぉぉおおお!!』が返って来ます。
"こぉぉぉぉおおお!!".replace(/a?/, "うん"); // 文字列『うんこぉぉぉぉおおお!!』が返って来ます。
"こぉぉぉぉおおお!!".replace(/b?/, "うん"); // 文字列『うんこぉぉぉぉおおお!!』が返って来ます。

『*』と『?』は手前の一文字のみの影響を受けますので、手前の文字が二文字以上だった場合は多分イメージ通りの動きになります。

"こぉぉぉぉおおお!!".replace(/ああ*/, "うん"); // これは特定されません。

ここまでは大丈夫そうでしょうか。

ではちょっと応用技です。先ほど紹介した何でも良い一文字を表現できる『.』がありましたよね。これを『*』、『+』、『?』と組み合わせることで「なんでも良い文字の繰り返し」を特定することができます。こんな感じですね。

// 『者』より後にどんな文字列が来ても置換されます。
"趣味でヒーローをやっている者なり。".replace(/者.*/, "者だ。"); // 文字列『趣味でヒーローをやっている者だ。』が返って来ます。
"趣味でヒーローをやっている者でござる。".replace(/者.*/, "者だ。"); // 文字列『趣味でヒーローをやっている者だ。』が返って来ます。
"趣味でヒーローをやっている者だクポー。".replace(/者.*/, "者だ。"); // 文字列『趣味でヒーローをやっている者だ。』が返って来ます。
"趣味でヒーローをやっている者だっちゃ。".replace(/者.*/, "者だ。"); // 文字列『趣味でヒーローをやっている者だ。』が返って来ます。
"趣味でヒーローをやっている者".replace(/者.*/, "者だ。"); // 文字列『趣味でヒーローをやっている者だ。』が返って来ます。

// 『趣味で』で始まり『をやっている者だ。』で終わるものが全て置換されます。
"趣味でプログラマーをやっている者だ。".replace(/趣味で.*をやっている者だ。/, "趣味でヒーローをやっている者だ。"); // 文字列『趣味でヒーローをやっている者だ。』が返って来ます。
"趣味でデザイナーをやっている者だ。".replace(/趣味で.*をやっている者だ。/, "趣味でヒーローをやっている者だ。"); // 文字列『趣味でヒーローをやっている者だ。』が返って来ます。
"趣味で怪人をやっている者だ。".replace(/趣味で.*をやっている者だ。/, "趣味でヒーローをやっている者だ。"); // 文字列『趣味でヒーローをやっている者だ。』が返って来ます。

// 『者』より後に何か一文字以上の文字があればその部分が置換されます。
"趣味でヒーローをやっている者なり。".replace(/者.+/, "者だ。"); // 文字列『趣味でヒーローをやっている者だ。』が返って来ます。
"趣味でヒーローをやっている者でござる。".replace(/者.+/, "者だ。"); // 文字列『趣味でヒーローをやっている者だ。』が返って来ます。
"趣味でヒーローをやっている者だクポー。".replace(/者.+/, "者だ。"); // 文字列『趣味でヒーローをやっている者だ。』が返って来ます。
"趣味でヒーローをやっている者だっちゃ。".replace(/者.+/, "者だ。"); // 文字列『趣味でヒーローをやっている者だ。』が返って来ます。
"趣味でヒーローをやっている者".replace(/者.+/, "者だ。"); // これは置換されず、文字列『趣味でヒーローをやっている者』が返って来ます。

// 『者』より後に何か一文字、または文字が存在しなければその部分が置換されます。
"趣味でヒーローをやっている".replace(/者.?/, "者だ。"); // これは置換されず、文字列『趣味でヒーローをやっている者』が返って来ます。
"趣味でヒーローをやっている者".replace(/者.?/, "者だ。"); // 文字列『趣味でヒーローをやっている者だ。』が返って来ます。
"趣味でヒーローをやっている者。".replace(/者.?/, "者だ。"); // 文字列『趣味でヒーローをやっている者だ。』が返って来ます。
"趣味でヒーローをやっている者だ".replace(/者.?/, "者だ。"); // 文字列『趣味でヒーローをやっている者だ。』が返って来ます。
"趣味でヒーローをやっている者だよん。".replace(/者.?/, "者だ"); // 文字列『趣味でヒーローをやっている者だよん。』が返って来ます。

これめっちゃ強力なんでバッチリ使いこなしてしまって下さい。

{}』を使用すると繰り返しの文字列をもっと細かく特定することができます。

『{n,m}』と記述すると直前の要素のn回からm回までの繰り返しを、『{n,}』と記述すると直前の要素のn回以上の繰り返しを、『{n}』と記述すると直前の要素のn回だけの繰り返しを特定します。

こんな感じですね。

"aaaaa".replace(/a{0,5}/, "x"); // 文字列『x』が返って来ます。
"aaaa".replace(/a{0,5}/, "x"); // これは特定されません。

"aaaaa".replace(/a{5,}/, "x"); // 文字列『x』が返って来ます。
"aaaaaaaaa".replace(/a{5,}/, "x"); // 文字列『x』が返って来ます。
"aaaa".replace(/a{5,}/, "x"); // これは特定されません。

"aaaaa".replace(/a{5}/, "x"); // 文字列『x』が返って来ます。
"aaaa".replace(/a{5}/, "x"); // これは特定されません。

尚、『*』は『{0,}』、『+』は『{1,}』、『?』は『{0,1}』と記述していることと同じです。

続いて『文字列の最初』と『文字列の最後』を特定する『^』と『$』です。ひとつひとつ見ていきましょう。『^』の使い方はこんな感じですね。

"aaaaa".replace(/^a/, "x"); // 文字列『aaaaa』の最初の『a』が文字列『x』に変換され文字列『xaaaa』が返って来ます。

上記のサンプルですと『a』の前に『^』がついていますね。これで「最初の『a』」を特定することができます。これは二文字以上の文字と組み合わせた場合でも同じです。

"サイタマサイタマサイタマサイタマサイタマ".replace(/^サイタマ/, "ワンパンマン"); // 最初の『サイタマ』だけ置換されるので文字列『ワンパンマンサイタマサイタマサイタマサイタマ』が返って来ます。

続いて『$』の使い方を見ていきましょう。基本的には『^』の使い方と同じなんですが、『$』の場合は文字の後に『$』を付ける必要があります。文字の前ではありません。以下のような感じですね。

"aaaaa".replace(/a$/, "x"); // 文字列『aaaaa』の最後の『a』が文字列『x』に変換され文字列『aaaax』が返って来ます。
"サイタマサイタマサイタマサイタマサイタマ".replace(/サイタマ$/, "ワンパンマン"); // 最後の『サイタマ』だけ置換されるので文字列『サイタマサイタマサイタマサイタマワンパンマン』が返って来ます。

ここ間違いやすいので注意して下さい。

続いて『[]』を使ってみましょう。これは『[]』の中にある要素をそれぞれ特定できます。使い方はこんな感じです。

"a".replace(/[abc]/, "x"); // 文字列『x』が返って来ます。
"b".replace(/[abc]/, "x"); // 文字列『x』が返って来ます。
"c".replace(/[abc]/, "x"); // 文字列『x』が返って来ます。
"d".replace(/[abc]/, "x"); // これは特定されません。

上記のサンプルですと正規表現『[abc]』となっていますね。これは『a』、『b』、『c』だった場合に特定します。複数の文字や要素のまとまり(上記の場合だと単語「abc」)ではなく、一要素ごとに区切られるということに注意して下さい。

ちなみに『[]』でまとめられたものは『文字クラス』と呼ばれます。ちょっとややこしいのですが、先ほどの『\s』や『\d』なども『文字クラス』と呼ばれ、こちらは『文字クラスの略記法』に該当します。こちらは参考書などで呼び方が違う場合がありますのでご注意下さい。現場ではあんまり使われない言葉です。

そして『0』から『9』までの数値や、『a』から『z』までのアルファベットなどを特定したい場合に『[0123456789]』と書いたり、『[abcdefghijklmnopqrstuvwxyz]』と書いても良いのですが、任意の開始文字と『-』と任意の終了文字を記述することでさくっと特定することができます。こんな感じですね。

// 『0123456789』だった場合に特定します。
"0".replace(/[0-9]/, "x"); // 文字列『x』が返って来ます。
"1".replace(/[0-9]/, "x"); // 文字列『x』が返って来ます。
"2".replace(/[0-9]/, "x"); // 文字列『x』が返って来ます。
"3".replace(/[0-9]/, "x"); // 文字列『x』が返って来ます。
"4".replace(/[0-9]/, "x"); // 文字列『x』が返って来ます。
"5".replace(/[0-9]/, "x"); // 文字列『x』が返って来ます。
"6".replace(/[0-9]/, "x"); // 文字列『x』が返って来ます。
"7".replace(/[0-9]/, "x"); // 文字列『x』が返って来ます。
"8".replace(/[0-9]/, "x"); // 文字列『x』が返って来ます。
"9".replace(/[0-9]/, "x"); // 文字列『x』が返って来ます。

// 『012』だった場合に特定します。
"0".replace(/[0-2]/, "x"); // 文字列『x』が返って来ます。
"1".replace(/[0-2]/, "x"); // 文字列『x』が返って来ます。
"2".replace(/[0-2]/, "x"); // 文字列『x』が返って来ます。
"3".replace(/[0-2]/, "x"); // これは特定されません。

// 『abcdefghijklmnopqrstuvwxyz』だった場合に特定します。
"a".replace(/[a-z]/, "x"); // 文字列『x』が返って来ます。
"b".replace(/[a-z]/, "x"); // 文字列『x』が返って来ます。
"c".replace(/[a-z]/, "x"); // 文字列『x』が返って来ます。
"z".replace(/[a-z]/, "x"); // 文字列『x』が返って来ます。

// 『abc』だった場合に特定します。
"a".replace(/[a-c]/, "x"); // 文字列『x』が返って来ます。
"b".replace(/[a-c]/, "x"); // 文字列『x』が返って来ます。
"c".replace(/[a-c]/, "x"); // 文字列『x』が返って来ます。
"d".replace(/[a-c]/, "x"); // これは特定されません。

※ ちなみに『\d』は『[0-9]』、『\D』は『[^0-9]』と記述していることと同じです。

さらに『[あ-ん]』や『[ア-ン]』などと記述することでひらがなやカタカナなども特定することができます。ただし、使用言語や環境によってあいうえお順なのか辞書順なのかで違いがあったり、文字コードの影響を受けてしまったりと差が出やすい部分なので使用する際はしっかり動作を確認してから使用するようにしてください。

そして『[]』の中の先頭に『^』を記述することで『否定文字クラス』が表現できます。これは『[]』の中にある文字以外を特定する、といった動作になります。こんな感じですね。『^』は『[]』の中の先頭に記述しないとダメなのでご注意です。

"a".replace(/[^a]/, "x"); // これは特定されません。
"b".replace(/[^a]/, "x"); // 文字列『x』が返って来ます。
"c".replace(/[^a]/, "x"); // 文字列『x』が返って来ます。

"a".replace(/[^ab]/, "x"); // これは特定されません。
"b".replace(/[^ab]/, "x"); // これは特定されません。
"c".replace(/[^ab]/, "x"); // 文字列『x』が返って来ます。

"0".replace(/[^0-9]/, "x"); // これは特定されません。
"a".replace(/[^0-9]/, "x"); // 文字列『x』が返って来ます。

"0".replace(/[^a-z]/, "x"); // 文字列『x』が返って来ます。
"a".replace(/[^a-z]/, "x"); // これは特定されません。

尚、『[]』の中で『\d』や『\D』を記述することも可能です。『[]』の中で記述しても『\』と『d』の特定になったりせず、ちゃんと『\d』として特定してくれるのでご安心下さい。

"0".replace(/[\d]/, "x"); // 文字列『x』が返って来ます。
"9".replace(/[\d]/, "x"); // 文字列『x』が返って来ます。

ちょっと注意点ですが、『[]』の中に『^』と『-』と『\』以外のメタ文字を書いてもその文字はメタ文字として扱われません。例えば『.』と『*』を特定したいといった場合はこうなります。

".".replace(/[.*]/, "x"); // 文字列『x』が返って来ます。
"*".replace(/[.*]/, "x"); // 文字列『x』が返って来ます。

エスケープさせるために『\.』とか『\*』と記述しなくても特定できていますね。

『-』を特定したい場合は『0-9』といったように『-』の左側に何か文字が存在していない場合のみただの記号として扱われます。言葉にするとややこしいのでサンプルを見て下さい。こんな感じです。

// 『0』と『9』と『-』を特定したい場合は『-』の左側に文字を置かないように記述します。
"0".replace(/[-09]/, "x"); // 文字列『x』が返って来ます。
"9".replace(/[-09]/, "x"); // 文字列『x』が返って来ます。
"-".replace(/[-09]/, "x"); // 文字列『x』が返って来ます。
"5".replace(/[-09]/, "x"); // これは特定されません。

// こうするとダメです。『0123456789』が特定されちゃいます。
"0".replace(/[0-9]/, "x"); // 文字列『x』が返って来ます。
"9".replace(/[0-9]/, "x"); // 文字列『x』が返って来ます。
"-".replace(/[0-9]/, "x"); // これは特定されません。
"5".replace(/[0-9]/, "x"); // 文字列『x』が返って来ます。

// 『\-』と記述してもOKです。
"0".replace(/[0\-9]/, "x"); // 文字列『x』が返って来ます。
"9".replace(/[0\-9]/, "x"); // 文字列『x』が返って来ます。
"-".replace(/[0\-9]/, "x"); // 文字列『x』が返って来ます。
"5".replace(/[0\-9]/, "x"); // これは特定されません。

『\』を特定したい場合は『\\』と記述して下さい。

"\\".replace(/[\\]/, "x"); // 文字列『x』が返って来ます。

『^』は『[]』の中の先頭に記述してあった場合は否定文字クラスを表現するメタ文字になっちゃうので『^』という記号を特定したい場合は先頭以外で記述するか、『\^』と記述するようにして下さい。

"^".replace(/[\^]/, "x"); // 文字列『x』が返って来ます。
"^".replace(/[abc^]/, "x"); // 文字列『x』が返って来ます。

と、こんな感じで単純な記号の特定を行う時は色々とややこしいです。なので、ちょっと荒業ですが記号の前には全部『\』を置いちゃってOKかもしれません。

「ソースコードを1文字レベルで切り詰めてファイル量を節約したい」といった場合はNGですが、通常の場合や急いでる時などは記号の前に全部『\』を置いちゃっても実質的な問題は発生しません。これは色々な参考書や公式サイト等でも推薦されているやり方なので覚えておいて下さい。

// 記号の前に『\』を置いちゃえばとりあえずは動きます。
"^".replace(/[\^\.\*\?]/, "x");
".".replace(/[\^\.\*\?]/, "x");
"*".replace(/[\^\.\*\?]/, "x");
".".replace(/[\^\.\*\?]/, "x");

続いて『|』を使ってみましょう。これは『いずれかの文字』を特定できるメタ文字になります。以下のサンプルを見て下さい。

"a".replace(/a|b|c/, "x"); // 文字列『x』が返って来ます。
"b".replace(/a|b|c/, "x"); // 文字列『x』が返って来ます。
"c".replace(/a|b|c/, "x"); // 文字列『x』が返って来ます。

上記のサンプルでは文字列『a』、または『b』、または『c』だった場合に置換されます。以下の場合は置換されません。

"d".replace(/a|b|c/, "x"); // これは特定されません。

これは複数の文字になっても同じです。ここが『[]』の動作とちょっと違うので注意です。

"趣味でプログラマーをやっている者だ。".replace(/プログラマー|デザイナー|怪人/, "ヒーロー"); // 文字列『趣味でヒーローをやっている者だ。』が返って来ます。
"趣味でデザイナーをやっている者だ。".replace(/プログラマー|デザイナー|怪人/, "ヒーロー"); // 文字列『趣味でヒーローをやっている者だ。』が返って来ます。
"趣味で怪人をやっている者だ。".replace(/プログラマー|デザイナー|怪人/, "ヒーロー"); // 文字列『趣味でヒーローをやっている者だ。』が返って来ます。

続いて『()』を使ってみましょう。これは複数の文字や要素をひとまとめにするという機能になります。こんな感じですね。

"あいうえおabcabcabc".replace(/あいうえお(abc)*/, "x"); // 文字列『x』が返って来ます。

0回以上の繰り返しを特定する『*』の前に『(abc)』と記述されていますね。『()』で『abc』を囲んであげることで『abc』という文字をひとまとめにして特定することができます。

例えば「javascript」と「Javascript」と「javaScript」と「JavaScript」を特定したい場合はこういう記述になります。

"javascript".replace(/[jJ]ava([sS]cript)+/, "x"); // 文字列『x』が返って来ます。
"Javascript".replace(/[jJ]ava([sS]cript)+/, "x"); // 文字列『x』が返って来ます。
"javaScript".replace(/[jJ]ava([sS]cript)+/, "x"); // 文字列『x』が返って来ます。
"JavaScript".replace(/[jJ]ava([sS]cript)+/, "x"); // 文字列『x』が返って来ます。

括弧だらけでややこしいですが頑張って下さい。複雑な『正規表現』は長年やっている人でも読むのが大変だったりしますのでここは気合で乗りきましょう。

『|』などで複数のキーワードを指定した場合はより左側に記述されたキーワードが優先されます。

例えば正規表現『a|ab|abc』で文字列『abc』を置換した場合は『a』の部分のみが置換されます。

"abc".replace(/a|ab|abc/, "x"); // 文字列『xbc』が返って来ます。

なので優先的に処理させたいキーワードを左から順番に並べるようにしましょう。

というわけで長くなりましたが以上になります。このくらいの『正規表現』を抑えておけばよほど複雑な文字列でない限りは特定できるようになっているはずです。

尚、再度確認させていただきますが今回の記事で紹介した『正規表現』はJavaScript専用となります。他の言語等で使用する『正規表現』とは違う場合が多いのでそこはご注意です。

続いての記事では『プリミティブ』と『オブジェクト』について色々とやっていきたいと思います。ではではこの辺で。またお会いしましょう。

この記事は桜舞が執筆致しました。

著者が愛する小型哺乳類

桜舞 春人 Sakurama Haruto

ISDN時代から様々なコンテンツを制作しているちょっと髪の毛が心配な東京在住のプログラマー。生粋のロングスリーパーで、10時間以上睡眠を取らないと基本的に体調が悪い。好きなだけ寝れる生活を送るのが夢。ゲームとスポーツと音楽が大好き。誰か髪の毛を分けて下さい。

記事の間違いや著作権の侵害等ございましたらお手数ですがまでご連絡頂ければ幸いです。