この記事は翻訳作業中です。
正規表現とは、文字列内で文字の組み合わせを照合するために用いられるパターンです。JavaScript では、正規表現はオブジェクトでもあります。これらのパターンは RegExp の exec および test メソッドや、String の match、 matchAll、replace、search、および split メソッドで使用できます。本章では、JavaScript の正規表現について説明します。
正規表現の作成
正規表現は 2 種類の方法で作成できます :
次のように、スラッシュによって囲まれたパターンからなる正規表現リテラルを使用します :
var re = /ab+c/;
正規表現リテラルはスクリプトのロード時にその正規表現をコンパイルします。正規表現が一定のままの場合、この方法を使うとよいパフォーマンスが得られます。
また、次のように RegExp オブジェクトのコンストラクタ関数を呼び出す方法があります :
var re = new RegExp('ab+c');
コンストラクタ関数を使用すると、実行時にその正規表現をコンパイルします。正規表現パターンが変わることがわかっている場合や、パターンがわからない場合、ユーザーが入力するなど別のソースからパターンを取得する場合は、コンストラクタ関数を使用してください。
正規表現パターンの記述
正規表現パターンは、/abc/ のような単純な文字、または /ab*c/ や /Chapter (\d+)\.\d*/ のような単純な文字と特殊文字との組み合わせからなります。最後の例には記憶装置として用いられる丸括弧があります。パターンのこの丸括弧で囲まれた部分でマッチした箇所は、後で使用できるように記憶されます。詳しくは括弧で囲まれた部分文字列のマッチの使用を参照してください。
単純なパターンの使い方
単純なパターンとは、直接マッチしている部分を見つけたい文字から構成されたものです。例えば /abc/ というパターンは、実際に 'abc' という文字が一緒にその順で存在しているときだけ、文字列中の文字の組み合わせにマッチします。"Hi, do you know your abc's?" や "The latest airplane designs evolved from slabcraft." といった文字列でのマッチは成功します。どちらの場合でも 'abc' という部分文字列にマッチします。"Grab crab" という文字列では、'abc' という部分文字列が含まれていないためマッチしません。
特殊文字の使い方
1 個以上の b を見つけたり、ホワイトスペースを見つけたりといった直接マッチより高度なマッチの検索では、パターンに特殊文字を使用します。例えば /ab*c/ というパターンでは、1 個の 'a' とその後ろに続く 0 個以上の 'b' (* は直前のアイテムの 0 回以上の出現を意味します)、そしてそのすぐ後ろに続く 'c' で構成される文字の組み合わせにマッチします。"cbbabbbbcdebc," という文字列では、このパターンは 'abbbbc' という部分文字列にマッチします。
以下のページで、正規表現で使用できる特殊文字の完全なリストとその意味を詳しく説明します。
- 言明
- 何らかの方法でマッチが可能なことを示します。言明は先読み、後読み、条件式を含みます。
- 境界
- 行や文字の始まり・終わりを示します。
- 文字クラス
- 文字や数字の区別など、文字の種類を区別します。
- グループと範囲
- 式にある文字のグループと範囲を示します。
- 数量詞
- マッチする文字や式の数を示します。
- Unicode プロパティエスケープ
- 大文字と小文字、数学記号、句読点など、Unicode文字のプロパティに基づき区別します。
エスケープする
もしあなたが特殊な文字を使う必要があるのなら(例えば実際に * を検索したい場合)、その文字の前にバックスラッシュを付けてエスケープする必要があります。例えば、a と * と b が続くのを検索する場合、/a\*b/ とします。これはバックスラッシュが * を特殊な文字ではなく、リテラルとして扱うようにエスケープしています。
類話として、もしあなたが正規表現リテラルを書いていて スラッシュ('/')とマッチさせる必要があるならば、スラッシュをエスケープする必要があります(そうしないとスラッシュがパターンを終了してしまいます)。例えば、"/example/"の文字列とそれに続く1つ以上のアルファベットを探すためには、/\/example\/[a-z]+/i とします。各スラッシュ前のバックスラッシュが、スラッシュをリテラルにしています。
To match a literal backslash, you need to escape the backslash. For instance, to match the string "C:\" where 'C' can be any letter, you'd use /[A-Z]:\\/—the first backslash escapes the one after it, so the expression searches for a single literal backslash.
If using the RegExp constructor with a string literal, remember that the backslash is an escape in string literals, so to use it in the regular expression, you need to escape it at the string literal level. /a\*b/ and new RegExp("a\\*b") create the same expression, which searches for 'a' followed by a literal '*' followed by 'b'.
エスケープ文字がパターンに追加されてないなら、String.replace を使用して追加することができます:
function escapeRegExp(string) {
return string.replace(/[.*+?^=!:${}()|[\]\/\\]/g, '\\$&'); // $&はマッチした部分文字列全体を意味します
}
正規表現の後の g はグローバルサーチを行うオプション/フラグで、全体の文字列を見てすべてのマッチを返します。下のフラグを用いた高度な検索に詳しく説明されています。
括弧の使い方
正規表現パターンの一部を括弧で囲むことで、マッチした部分文字列を記憶しておくことができます。いったん記憶されれば、後からその部分文字列を呼び出すことができます。これに関しては括弧で囲まれた部分文字列のマッチの使用で説明しています。
例として /Chapter (\d+)\.\d*/ というパターンを使い、エスケープ文字と特殊文字についても説明した上で、どのようにパターンの一部が記憶されるかを示します。これは 'Chapter ' という文字列に正確にマッチし、それに続く 1 文字以上の数字 (\d はいずれかの数字を、+ は 1 回以上の繰り返しを意味します)、それに続く小数点(それ自体は特殊文字であり、小数点の前の \ はパターンが '.' という文字そのものを探すようにすることを意味します)、それに続く 0 文字以上の数字 (\d は数字を、* は 0 回以上の繰り返しを意味します)にマッチします。さらに、最初にマッチした数字の記憶に括弧が使われています。
このパターンは "Open Chapter 4.3, paragraph 6" という文字列で検索され、'4' が記憶されます。このパターンは "Chapter 3 and 4" では見つかりません。この文字列は '3' の後にピリオドがないからです。
マッチした部分を記憶させることなく部分文字列にマッチさせたい場合は、その括弧においてパターンの前に ?: をつけてください。例えば (?:\d+) は 1 文字以上の数字にマッチしますが、マッチした文字列は記憶しません。
正規表現の使用
正規表現は、RegExp の test および exec メソッド、String の match、replace、search、split メソッドとともに使用します。これらのメソッドの詳細は JavaScript リファレンスで説明しています。
| メソッド | 説明 |
|---|---|
exec |
文字列中で一致するものを検索する RegExp のメソッドです。結果情報の配列を返します。 |
test |
文字列中で一致するものがあるかをテストする RegExp のメソッドです。true または false を返します。 |
match |
文字列中で一致するものを検索する String のメソッドです。結果情報の配列を返します。マッチしない場合は null を返します。 |
matchAll |
キャプチャグループを含んだ、すべてのマッチをもつ iterator を返す String のメソッドです。 |
search |
文字列中で一致するものがあるかをテストする String のメソッドです。マッチした場所のインデックスを返します。検索に失敗した場合は -1 を返します。 |
replace |
文字列中で一致するものを検索し、マッチした部分文字列を別の部分文字列に置換する String のメソッドです。 |
split |
正規表現または固定文字列を用いて文字列を分割し、部分文字列の配列に入れる String のメソッドです。 |
あるパターンが文字列に存在するかを知りたいときは、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'); // similar to "cdbbdbsbz".match(/d(b+)d/g); however,
// the latter outputs Array [ "dbbd" ], while
// /d(b+)d/g.exec('cdbbdbsbz') outputs Array [ 'dbbd', 'bb', index: 1, input: 'cdbbdbsbz' ].
(異なるふるまいの詳しい情報は g フラグによる振る舞いの違いを参照してください。)
ある文字列から正規表現を組み立てたい場合は、次のスクリプトのような方法があります:
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 プロパティの値も異なるのです。オブジェクト初期化子で作成する正規表現のプロパティにアクセスする必要がある場合は、まずそれを変数に代入するようにしてください。
括弧で囲まれた部分文字列のマッチの使用
正規表現パターンに括弧を含めることで、対応するサブマッチが記憶されます。例えば /a(b)c/ は 'abc' という文字列にマッチし、'b' が記憶されます。この括弧で囲まれた部分文字列のマッチは、Array の要素 [1], ..., [n] を使用して呼び出すことができます。
括弧で囲まれた部分文字列は何個でも使用できます。返された配列には、見つかったものすべてが存在します。以下の例では、括弧で囲まれた部分文字列の使用法を説明します。
次のスクリプトは replace() メソッドを使用して文字列中の単語を入れ替えます。テキスト置き換えのために、スクリプトで $1 と $2 を使用して、最初とその次の括弧で囲まれた部分文字列のマッチを示しています。
var re = /(\w+)\s(\w+)/; var str = 'John Smith'; var newstr = str.replace(re, '$2, $1'); console.log(newstr); // "Smith, John"
フラグを用いた高度な検索
正規表現には、グローバルな検索や大文字/小文字を区別しない検索を可能にする 4 種類のオプションフラグがあります。これらのフラグは、単独で使用することもまとめて使用することもできます。順番は問いません。フラグは正規表現の一部として含まれます。
| フラグ | 説明 | |
|---|---|---|
g |
グローバルサーチ。 | |
i |
大文字・小文字を区別しない検索。 | |
m |
複数行検索。 | |
s |
. を改行文字と一致するようにします。 |
|
u |
"unicode"; パターンをユニコードのコードポイントの連続として扱う | |
y |
対象文字列で最後に見つかったマッチの位置から検索を開始する先頭固定 (sticky) 検索を行います。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');
に置き換えることができます。得られる結果は同じです。
.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"]
m フラグは複数行の入力文字列が複数行として扱われるように使われます。m が使われた場合、^ と $ は文字列全体の最初と最後の代わりに、入力文字列内のあらゆる行の開始と終了にマッチします。
例
以下では、正規表現の使用法をいくつか例示します。
入力文字列の順序変更
次の例では、正規表現の構造と string.split() および string.replace() の使用法を示します。空白、タブ、1 個のセミコロンで分割された名前(ファーストネームが先頭)からなる、大まかに整形された入力文字列をきれいにフォーマットします。最終的に名前の順序を逆転し(ラストネームが先頭)、リストをソートします。
// 名前の文字列は複数の空白やタブを含む。
// また、ファーストネームとラストネームの間に複数の空白があることもある
var names = 'Orange Trump ;Fred Barney; Helen Rigby ; Bill Abel ; Chris Hand ';
var output = ['---------- Original String\n', names + '\n'];
// 2 種類の正規表現パターンと、格納用の配列を用意する。
// 文字列を分割して配列の要素に収める。
// パターン: ホワイトスペースの 0 回以上の繰り返しのあとにセミコロン、そのあとにホワイトスペースの 0 回以上の繰り返し
var pattern = /\s*;\s*/;
// 上記のパターンで文字列を断片に分割し、
// nameList という配列に断片を格納する。
var nameList = names.split(pattern);
// 新たなパターン: 1 個以上の文字、1 個以上のホワイトスペース、1 個以上の文字
// 括弧を用いてパターンの断片を記憶する。
// 記憶した断片は後から参照される。
pattern = /(\w+)\s+(\w+)/;
// 処理された名前を格納する新しい配列。
var bySurnameList = [];
// 名前の配列を表示し、新しい配列にカンマ区切りで名前を
// ラストネーム、ファーストネームの順で格納する。
//
// replace メソッドはパターンにマッチしたものを除去し、
// 「2 番目の記憶文字列のあとにカンマとスペース、
// さらにその後に続く 1 番目の記憶文字列」に置き換える。
//
// 変数 $1 および $2 は、パターンにマッチさせた際に
// 記憶しておいた部分文字列を参照する
output.push('---------- After Split by Regular Expression');
var i, len;
for (i = 0, len = nameList.length; i < len; i++){
output.push(nameList[i]);
bySurnameList[i] = nameList[i].replace(pattern, '$2, $1');
}
// 新しい配列を表示する。
output.push("---------- Names Reversed");
for (i = 0, len = bySurnameList.length; i < len; i++){
output.push(bySurnameList[i]);
}
// ラストネームについてソートし、ソートした配列を表示する。
bySurnameList.sort();
output.push('---------- Sorted');
for (i = 0, len = bySurnameList.length; i < len; i++){
output.push(bySurnameList[i]);
}
output.push('---------- End');
console.log(output.join('\n'));
特殊文字を用いた入力の確認
次の例では、ユーザーは電話番号を入力します。ユーザーが "Check" ボタンを押すと、スクリプトがその番号の妥当性を確認します。その番号が正当である(正規表現で指定した文字の連続にマッチする)場合、スクリプトはユーザーへの感謝のメッセージを表示し、その番号を承認します。番号が正当でない場合は、その番号が妥当でないことをユーザーに通知します。
正規表現は、0 または 1 個の左括弧 \(?、その後に 3 個の数字 \d{3}、その後に 0 または 1 個の右括弧 \)?、その後、見つかった際に記憶される 1 個のダッシュ、スラッシュ、または小数点 ([-\/\.])、その後に 3 個の数字 \d{3}、その後、記憶された 1 個のダッシュ、スラッシュ、または小数点のマッチ \1、その後に 4 個の数字を探します。
ユーザーが Enter ボタンを押した際に発動する Change イベントにより phoneInput.value の値が設定されます。
<!DOCTYPE html>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
<meta http-equiv="Content-Script-Type" content="text/javascript">
<script type="text/javascript">
var re = /\(?:\d{3}|\(\d{3}\))([-\/\.])\d{3}\1\d{4}/;
function testInfo(phoneInput){
var OK = re.exec(phoneInput.value);
if (!OK)
window.alert(phoneInput.value + " isn't a phone number with area code!");
else
window.alert("Thanks, your phone number is " + OK[0]);
}
</script>
</head>
<body>
<p>Enter your phone number (with area code) and then click "Check".
<br>The expected format is like ###-###-####.</p>
<form action="#">
<input id="phone"><button onclick="testInfo(document.getElementById('phone'));">Check</button>
</form>
</body>
</html>

