正規表現

正規表現とは、文字列内で文字の組み合わせを照合するために用いられるパターンです。 JavaScript では、正規表現はオブジェクトでもあります。これらのパターンは RegExpexec() および test() メソッドや、Stringmatch()、 matchAllreplacesearchsplit メソッドで使用できます。本章では、 JavaScript の正規表現について説明します。

正規表現の作成

正規表現は 2 通りの方法で作成することができます。

  • 次のように、スラッシュで囲まれたパターンからなる正規表現リテラルを使用します。

    let re = /ab+c/;
    

    正規表現リテラルはスクリプトの読み込み時にその正規表現をコンパイルします。正規表現が変化しない場合、この方法を使うとよいパフォーマンスが得られます。

  • また、次のように RegExp オブジェクトのコンストラクター関数を呼び出す方法があります。

    let re = new RegExp('ab+c');
    

    コンストラクター関数を使用すると、実行時にその正規表現をコンパイルします。正規表現パターンが変わることが分かっている場合や、パターンが分からない場合、ユーザー入力など別なところからパターンを取得する場合は、コンストラクター関数を使用してください。

正規表現パターンの記述

正規表現パターンは、/abc/ のような単純な文字、または /ab*c//Chapter (\d+)\.\d*/ のような単純な文字と特殊文字との組み合わせからなります。最後の例には記憶装置として用いられる丸括弧があります。パターンのこの丸括弧で囲まれた部分に一致した箇所は、後で使用できるように記憶されます。詳しくはグループの使用を参照してください。

注: すでに正規表現の形式に慣れている方は、早見表 (en-US)を見て特定のパターンや構造を素早く検索することもできます。

単純なパターンの使い方

単純なパターンとは、直接一致するものを探したい文字で構成されたものです。例えば /abc/ というパターンは、文字列の中で "abc" という並びが正確に現れる (すべての文字が連続しており、その順で並んでいる) 場合のみ、文字の組み合わせに一致します。 "Hi, do you know your abc's?""The latest airplane designs evolved from slabcraft." 等の文字列には一致します。どちらの場合でも、 "abc" という部分文字列に一致します。 "Grab crab" という文字列の場合、 "ab c" という部分文字列を含んでいますが、正確な "abc" という部分文字列を含んでいるわけではないので、一致しません。

特殊文字の使い方

直接の一致よりも高度な何かに一致するものを検索する場合、例えば 1 個以上の b を探したり、ホワイトスペースを見つけたりする場合、パターンに特殊文字を含めることができます。例えば、 1 個の "a" に 0 個以上の "b" が続き、さらに "c" が続くものに一致させる場合、 /ab*c/ というパターンを使用するでしょう。 "b" の後の * は「直前のアイテムの 0 回以上の出現」を意味します。 "cbbabbbbcdebc" という文字列では、このパターンは "abbbbc" という部分文字列に一致します。

以下のページで、正規表現で使用できる特殊文字の完全なリストとその意味を詳しく説明します。

言明
言明には、 行や単語の始まりや終わりを示す境界や、 (先読み、後読み、条件式を含む) 何らかの方法で一致できることを示す、その他のパターンが含まれます。
文字クラス
文字や数字の区別など、文字の種類を区別します。
グループと範囲
式にある文字のグループと範囲を示します。
数量詞
一致させる文字や式の数を示します。
Unicode プロパティエスケープ (en-US)
大文字と小文字、数学記号、句読点など、 Unicode 文字のプロパティに基づき区別します。

正規表現で利用可能なすべての特殊文字を一つの表で見たい場合は、以下を参照してください。

正規表現における特殊文字
文字 / 構造 対応する記事
\, ., \cX, \d, \D, \f, \n, \r, \s, \S, \t, \v, \w, \W, \0, \xhh, \uhhhh, \uhhhhh, [\b]

文字クラス

^, $, x(?=y), x(?!y), (?<=y)x, (?<!y)x, \b, \B

言明

(x), (?:x), (?<Name>x)x|y, [xyz], [^xyz], \Number

グループと範囲

*, +, ?, x{n}, x{n,}, x{n,m}

数量詞

\p{UnicodeProperty}, \P{UnicodeProperty} Unicode プロパティエスケープ (en-US)

注: もっと大きな早見表もあります (en-US) (個別の記事の一部を集約しただけです)。

エスケープ

特殊文字を文字として使う必要がある場合 (例えば、実際に "*" を検索する場合)、その前にバックスラッシュを付けてエスケープする必要があります。例えば、 "a""*" が続き、さらに "b" が続くものを検索するには、 /a\*b/ と使用します。バックスラッシュは "*" を「エスケープ」し、特殊文字ではなく文字として扱うようにします。

同様に、もし正規表現リテラルを書いていてスラッシュ ('/') に一致させる必要がある場合は、スラッシュをエスケープする必要があります (そうしないとスラッシュでパターンが終了します)。例えば、 "/example/" という文字列とそれに続く 1 文字以上のアルファベットを探すには、 /\/example\/[a-z]+/i とします。それぞれのスラッシュ前のバックスラッシュが、スラッシュを文字として扱わせます。

バックスラッシュ文字に一致させるには、バックスラッシュをエスケープする必要があります。例えば、 "C:\" という文字列で "C" が任意の英字になる場合は、 /[A-Z]:\\/ を使用します。最初のバックスラッシュがその次の文字をエスケープするので、この表現は単一のバックスラッシュを検索します。

RegExp コンストラクターに文字列リテラルを渡して使用する場合は、バックスラッシュは文字列リテラルでのエスケープ文字でもあることを思い出してください。つまり、バックスラッシュを正規表現で用いるには文字列リテラルレベルでエスケープする必要があります。 /a\*b/new RegExp("a\\*b") は同じ表現を生成するものであり、 "a" の次に "*"、その次に "b" があるものを探します。

エスケープ文字がパターンにまだ含まれていない場合は、 String.replace を使用して追加することができます。

function escapeRegExp(string) {
  return string.replace(/[.*+?^=!:${}()|[\]\/\\]/g, '\\$&'); // $&はマッチした部分文字列全体を意味します
}

正規表現の後の "g" はグローバルサーチを行うオプション/フラグで、文字列全体を見て一致したものをすべて返します。下のフラグを用いた高度な検索に詳しく説明されています。

なぜこれが JavaScript に組み込まれていないのかって? RegExp に追加する提案がありますが、 TC39 で拒絶されました

括弧の使用

正規表現パターンの一部を括弧で囲むことで、マッチした部分文字列を記憶しておくことができます。いったん記憶されれば、後からその部分文字列を呼び出すことができます。これに関してはグループと範囲で説明しています。

JavaScriptでの正規表現の使い方

正規表現は、RegExptest()exec() メソッド、Stringmatch()replace()search()split() メソッドとともに使用します。これらのメソッドの詳細は JavaScript リファレンスで説明しています。

正規表現を使用するメソッド
メソッド 説明
exec() 文字列内で一致するものの検索を実行します。結果情報の配列を返します。一致するものがなければ null を返します。
test() 文字列内で一致するものがあるか検査します。 true または false を返します。
match() キャプチャグループを含む、すべての一致するものを含む配列を返します。一致するものがない場合は null を返します。
matchAll() キャプチャグループを含む、すべての一致するものを含む反復子を返します。
search() 文字列内で一致するものがあるか検査します。一致した位置を返します。検索に失敗した場合は -1 を返します。
replace() 文字列内で一致するものを一つ検索し、一致した部分文字列を置換する部分文字列で置換します。
replaceAll() 文字列内で一致するものすべてを一つ検索し、一致した部分文字列を置換する部分文字列で置換します。
split() 正規表現または固定文字列を用いて文字列を分割し、部分文字列の配列に入れます。

あるパターンが文字列に存在するかを知りたいときは、test() または search() メソッドを使用してください。詳細な情報が知りたいときは (実行時間が長くなりますが) exec() または match() メソッドを使用してください。exec()match() を使用して一致した場合、これらのメソッドは配列を返し、関連する正規表現オブジェクトと定義済みオブジェクトである RegExp オブジェクトのプロパティを更新します。一致しなかった場合、 exec メソッドは null (false に変換される値) を返します。

次の例では、exec() メソッドを使用して文字列を検索します。

var myRe = /d(b+)d/g;
var myArray = myRe.exec('cdbbdbsbz');

正規表現のプロパティにアクセスする必要がない場合、 myArray を作成するもう一つの方法はこのスクリプトの通りです。

var myArray = /d(b+)d/g.exec('cdbbdbsbz');
    // "cdbbdbsbz".match(/d(b+)d/g) と同様。ただし、
    // "cdbbdbsbz".match(/d(b+)d/g) は配列 [ "dbbd" ] を出力するのに対し、
    // /d(b+)d/g.exec('cdbbdbsbz') は配列 [ 'dbbd', 'bb', index: 1, input: 'cdbbdbsbz' ] を出力する。

(異なる動作についての詳しい情報はexec() のグローバル検索フラグの使用を参照してください。)

ある文字列から正規表現を組み立てたい場合は、次のスクリプトのような方法があります。

var myRe = new RegExp('d(b+)d', 'g');
var myArray = myRe.exec('cdbbdbsbz');

これらのスクリプトでは一致したものがあると、配列を返すとともに次表で示されるプロパティを更新します。

正規表現の実行結果
オブジェクト プロパティまたはインデックス 説明 この例の場合
myArray 一致した文字列と、すべての記憶された部分文字列です。 ['dbbd', 'bb', index: 1, input: 'cdbbdbsbz']
index 入力文字列で一致した位置を示す、0 から始まるインデックスです。 1
input 元の文字列です。 'cdbbdbsbz'
[0] 最後に一致した文字列です。 'dbbd'
myRe lastIndex 次の検索が始まるインデックスです。 (このプロパティは、g オプションを用いる正規表現でのみセットされます。これについてはフラグを用いた高度な検索で説明します。) 5
source パターンのテキストです。正規表現の実行時ではなく作成時に更新されます。 'd(b+)d'

この例の 2 つ目の形式で示したように、オブジェクト初期化子で作成した正規表現は、変数に代入せずに使用することができます。しかし、そうすると出現するたびに新しい正規表現になります。このため、変数に代入せずにこの形式を使用すると、その後、その正規表現のプロパティにアクセスできません。例えば、次のようなスクリプトがあるとします。

var myRe = /d(b+)d/g;
var myArray = myRe.exec('cdbbdbsbz');
console.log('The value of lastIndex is ' + myRe.lastIndex);

// "The value of lastIndex is 5"

しかし、このスクリプトの場合は次のようになります。

var myArray = /d(b+)d/g.exec('cdbbdbsbz');
console.log('The value of lastIndex is ' + /d(b+)d/g.lastIndex);

// "The value of lastIndex is 0"

この 2 つの文中の /d(b+)d/g は異なる正規表現オブジェクトであるため、 lastIndex プロパティの値も異なります。オブジェクト初期化子で作成した正規表現のプロパティにアクセスする必要がある場合は、まずその正規表現を変数に代入する必要があります。

フラグを用いた高度な検索

正規表現には、グローバル検索や大文字小文字を区別しない検索などの機能を実現する 6 種類のオプションフラグがあります。これらのフラグは、個別に使用することも一緒に使用することもでき、順序は問いません。正規表現の一部に含まれます。

正規表現フラグ
フラグ 説明 対応するプロパティ
d 一致した部分文字列の位置を生成します。 RegExp.prototype.hasIndices
g グローバル検索を行います。 RegExp.prototype.global
i 大文字・小文字を区別しない検索です。 RegExp.prototype.ignoreCase
m 複数行の検索です。 RegExp.prototype.multiline
s . を改行文字と一致するようにします。 RegExp.prototype.dotAll
u "unicode" です。パターンを一連の Unicode コードポイントとして扱います。 RegExp.prototype.unicode
y 対象文字列の現在の位置から始まる部分に一致するものを探す「先頭固定」 (sticky) 検索を行います。 sticky のページを参照してください。 RegExp.prototype.sticky

フラグを正規表現に含めるには、次のようにしてください。

var re = /pattern/flags;

または

var re = new RegExp('pattern', 'flags');

フラグは正規表現を作る際になくてはならないものであることに注意してください。後から加えたり取り除いたりすることはできません。

例えば re = /\w+\s/g は、1 個以上の文字とそれに続くスペースを探す正規表現を作成します。また、正規表現は文字列全体を通してこの組み合わせを探します。

var re = /\w+\s/g;
var str = 'fee fi fo fum';
var myArray = str.match(re);
console.log(myArray);

// ["fee ", "fi ", "fo "]

この例ではこの行、

var re = /\w+\s/g;

をこの行、

var re = new RegExp('\\w+\\s', 'g');

に置き換えることができます。得られる結果は同じです。

m フラグは、複数行の入力文字列を複数行として扱うことを指定するために使用します。 m フラグを使用すると、 ^$ は、文字列全体ではなく、入力文字列内の任意の行の先頭または末尾に一致します。

exec() におけるグローバル検索の使用

.exec() メソッドが使われた時には g フラグに関連する動作が異なります。。 "class" と "argument" の役割が反対になります。 .match() の場合、文字クラス(やデータ型) がメソッドを持ち、正規表現は単なる引数で、 .exec() の場合、正規表現がメソッドを持ち、文字列は引数になります。この str.match(re)re.exec(str) を比較してみましょう。 g フラグが .exec() メソッドで使用されると、反復的な進行を行うことができます。

var xArray; while(xArray = re.exec(str)) console.log(xArray);
// produces:
// ["fee ", index: 0, input: "fee fi fo fum"]
// ["fi ", index: 4, input: "fee fi fo fum"]
// ["fo ", index: 7, input: "fee fi fo fum"]

注: 複数の例が次の場所にあります。

特殊文字を用いた入力の確認

次の例では、ユーザーが電話番号を入力することを想定しています。ユーザーが [チェック] ボタンを押すと、スクリプトはその番号の有効性をチェックします。番号が有効な場合 (正規表現で指定された文字列に一致した場合)、スクリプトはユーザーへの感謝と番号の確認を示すメッセージを表示します。番号が無効な場合、スクリプトはユーザーに電話番号が無効であることを通知します。

この正規表現は次のものを探します。

  1. 3 桁の数字 \d{3} または | 左括弧 \( の次に 3 桁の数字 \d{3} の次に閉じ括弧 \) で、これはキャプチャグループでないもの (?:) に入っています。
  2. 続いてダッシュ 1 つ、スラッシュ、小数点のうちの何れかがキャプチャグループ () に入っているもの
  3. 続いて 3 桁の数字 \d{3}
  4. 続いて (最初の) キャプチャグループ内で記憶されているものに一致するもの \1
  5. 続いて 4 桁の数字 \d{4}

ユーザーが Enter ボタンを押した際に起動する click イベントにより phoneInput.value の値が設定されます。

HTML

<p>
  電話番号(市外局番含む)を入力して "チェック" をクリックしてください。
  <br>
  適切な形式は ###-###-#### などです。
</p>
<form action="#">
  <input id="phone">
    <button onclick="testInfo(document.getElementById('phone'));">チェック</button>
</form>

JavaScript

var re = /(?:\d{3}|\(\d{3}\))([-\/\.])\d{3}\1\d{4}/;
function testInfo(phoneInput) {
  var OK = re.exec(phoneInput.value);
  if (!OK) {
    console.error(phoneInput.value + ' は市外局番付き電話番号ではありません!');
  } else {
    console.log('ありがとう、あなたの電話番号は ' + OK[0]);
  }
} 

結果

ツール

RegExr
An online tool to learn, build, & test Regular Expressions.
Regex tester
An online regex builder/debugger
Regex visualizer
An online visual regex tester.