Core JavaScript 1.5 Guide:Regular Expressions
出典: MDC
目次 |
[編集] 正規表現の作成
正規表現は 2 つの方法で作ることができます。
- 次のように、正規表現リテラルを使用する。
re = /ab+c/;
- 正規表現リテラルでは、スクリプトが評価されるときにその正規表現をコンパイルします。正規表現を定数として残しておくときは、この方法を使用するとよりよいパフォーマンスが得られます。
- 次のように、RegExp オブジェクトのコンストラクタ関数を呼び出す。
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' という部分文字列にマッチします。
以下の表で正規表現で使用できる特殊文字とその意味を詳しく説明します。
| 文字 | 意味 |
|---|---|
| \ | 次のうちのどちらか。
|
| ^ | 入力の先頭にマッチする。複数行フラグが true にセットされている場合は、改行文字直後にもマッチする。
例えば、/^A/ は "an A" の 'A' にはマッチしないが、"An A" の最初の 'A' にはマッチする。 |
| $ | 入力の末尾にマッチする。複数行フラグが true にセットされている場合は、改行文字直前にもマッチする。
例えば、/t$/ は "eater" の 't' にはマッチしないが、"eat" の 't' にはマッチする。 |
| * | 直前の文字の 0 回以上の繰り返しにマッチする。
例えば、/bo*/ は "A ghost booooed" の 'boooo' や "A bird warbled" の 'b' にはマッチするが、"A goat grunted" ではマッチしない。 |
| + | 直前の文字の 1 回以上の繰り返しにマッチする。{1,} と同等。
例えば、/a+/ は "candy" の 'a' や、"caaaaaaandy" のすべての a にマッチする。 |
| ? | 直前の文字の 0 回か 1 回の繰り返しにマッチする。
例えば、 *、+、?、{} といった量指定子の直後に使用した場合、その量指定子をスキップ優先(最小回数にマッチ)にする。これはデフォルトとは逆であり、デフォルトは繰り返し優先(最大回数にマッチ)。 先読み表現内でも使用できるが、これはこの表の x(?=y) および x(?!y) にて説明。 |
| . | 小数点は改行文字以外のどの 1 文字にもマッチする。
例えば、/.n/ は "nay, an apple is on the tree" の 'an' や 'on' にはマッチするが、'nay' にはマッチしない。 |
| (x) | 'x' にマッチし、マッチしたものを記憶しておく。これはキャプチャする括弧と呼ぶ。
例えば、/(foo)/ は "foo bar" の 'foo' にマッチし、これを記憶する。マッチした部分文字列は結果として生成される配列の要素 [1], ..., [n] から参照できる。 |
| (?:x) | 'x' にマッチするが、マッチしたものは記憶しない。これはキャプチャしない括弧と呼ぶ。マッチした部分文字列は先程のような配列の要素 [1], ..., [n] から参照することはできない。 |
| x(?=y) | 'x' に 'y' が続く場合のみ 'x' にマッチする。例えば、/Jack(?=Sprat)/ は 'Jack' の後ろに 'Sprat' が続く場合のみ 'Jack' にマッチする。/Jack(?=Sprat|Frost)/ は 'Jack' の後ろに 'Sprat' または 'Frost' が続く場合のみ 'Jack' にマッチする。しかしながら、'Sprat' も 'Frost' もマッチの結果には現れない。 |
| x(?!y) | 'x' に 'y' が続かない場合のみ 'x' にマッチする。例えば、/\d+(?!\.)/ はある数に小数点が続かない場合のみその数にマッチする。正規表現 /\d+(?!\.)/.exec("3.141") は 141 にはマッチするが 3.141 にはマッチしない。 |
| x|y | 'x' または 'y' にマッチする。
例えば、/green|red/ は "green apple" の "green' や "red apple" の 'red' にマッチする。 |
| {n} | n には正の整数が入る。直前の文字がちょうど n 回出現するものにマッチする。
例えば、/a{2}/ は "candy" の 'a' にはマッチしないが、"caandy" の すべての a にマッチする。また、"caaandy" の最初の 2 つの a にマッチする。 |
| {n,} | n には正の整数が入る。直前の文字が少なくとも n 回出現するものにマッチする。
例えば、/a{2,}/ は "candy" の 'a' にはマッチしないが、"caandy" や "caaaaaaandy" の すべての a にマッチする。 |
| {n,m} | n および m には正の整数が入る。直前の文字が少なくとも n 回、多くとも m 回出現するものにマッチする。
例えば、/a{1,3}/ は "cndy" ではマッチせず、"candy" の 'a'、"caandy" の最初の 2 つの a、"caaaaaaandy" の最初の 3 つの a にマッチする。"caaaaaaandy" では元の文字列に a が 4 つ以上あるが、マッチするのは "aaa" であることに注意。 |
| [xyz] | 文字の集合。囲まれた文字のどれにでもマッチする。ハイフンを用いて文字の範囲を指定することも可能。
例えば、[abcd] は [a-d] と同じ。これは "brisket" の 'b' や "ache" の 'c' にマッチする。 |
| [^xyz] | 文字の集合の否定または補集合。角括弧で囲まれていないものにマッチする。ハイフンを用いて文字の範囲を指定することも可能。
例えば、[^abc] は [^a-c] と同じ。これは "brisket" の 'r' や "chop" の 'h' にマッチする。 |
| [\b] | 後退にマッチする。(\b と混同してはならない。) |
| \b | スペースや改行文字のような単語の区切りにマッチする。([\b] と混同してはならない。)
例えば、/\bn\w/ は "noonday" の 'no' にマッチする。また、/\wy\b/ は "possibly yesterday" の 'ly' にマッチする。 |
| \B | 単語の区切り以外の文字にマッチする。
例えば、/\w\Bn/ は "noonday" の 'on' にマッチする。また、/y\B\w/ は "possibly yesterday" の 'ye' にマッチする。 |
| \cX | X には制御文字が入る。文字列中の制御文字にマッチする。
例えば、/\cM/ は文字列中の control-M にマッチする。 |
| \d | 数字にマッチする。[0-9] と同等。
例えば、/\d/ や /[0-9]/ は "B2 is the suite number" の '2' にマッチする。 |
| \D | 数字以外の文字にマッチする。[^0-9] と同等。
例えば、/\D/ や /[^0-9]/ は "B2 is the suite number" の 'B' にマッチする。 |
| \f | 改ページにマッチする。 |
| \n | 改行にマッチする。 |
| \r | 復帰にマッチする。 |
| \s | スペース、タブ、改ページ、改行を含む、1 つのホワイトスペース文字にマッチする。[ \f\n\r\t\v\u00A0\u2028\u2029] と同等。
例えば、/\s\w*/ は "foo bar" の ' bar' にマッチする。 |
| \S | ホワイトスペース以外の 1 文字にマッチする。[^ \f\n\r\t\v\u00A0\u2028\u2029] と同等。
例えば、/\S\w*/ は "foo bar" の 'foo' にマッチする。 |
| \t | タブにマッチする。 |
| \v | 垂直タブにマッチする。 |
| \w | アンダースコアを含むどの英数字にもマッチする。[A-Za-z0-9_] と同等。
例えば、/\w/ は "apple" の 'a' や "$5.28" の '5' や "3D" の '3' にマッチする。 |
| \W | 前述以外の文字にマッチする。[^A-Za-z0-9_] と同等。
例えば、/\W/ や /[^$A-Za-z0-9_]/ は "50%" の '%' にマッチする。 |
| \n | n には正の整数が入る。その正規表現の n 番目の括弧の部分にマッチする最後の部分文字列への後方参照(左括弧をカウントする)。
例えば、/apple(,)\sorange\1/ は "apple, orange, cherry, peach" の 'apple, orange,' にマッチする。 |
| \0 | NUL 文字にマッチする。この後ろに他の数字を続けてはならない。 |
| \xhh | hh(2 桁の 16 進数)というコードを持つ文字にマッチする。 |
| \uhhhh | hhhh(4 桁の 16 進数)というコードを持つ文字にマッチする。 |
表 4.1正規表現における特殊文字
[編集] 括弧の使用
正規表現パターンの一部分を括弧で囲むことで、マッチした部分文字列のその部分を記憶しておくことができます。一度記憶すると、後からその部分文字列を呼び戻すことができます。これに関しては 括弧で囲まれた部分文字列のマッチの使用 で説明しています。
例えば、/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 を返す。 |
| search | ある文字列でのマッチをテストする String のメソッド。マッチのインデックスを返す。検索に失敗した場合は -1 を返す。 |
| replace | ある文字列でのマッチの検索を実行し、マッチした部分文字列を別の部分文字列に置換する String のメソッド。 |
| split | 正規表現または固定文字列を用いてある文字列を分割し、部分文字列の配列にする String のメソッド。 |
表 4.2:正規表現を使用するメソッド
あるパターンが文字列に存在するかを知りたいときは test または search メソッドを使用してください。もっと情報が必要な場合(ただし実行が遅くなる)は exec または match メソッドを使用してください。exec や match を使用し、マッチが成功した場合は、これらのメソッドは配列を返し、結びつけられた正規表現オブジェクトと定義済み正規表現オブジェクト RegExp のプロパティを更新します。マッチが失敗すると exec メソッドは null(false に変換される)を返します。
次の例では、exec メソッドを使用して、文字列でマッチを見つけます。
<SCRIPT type="text/javascript">
myRe = /d(b+)d/g;
myArray = myRe.exec("cdbbdbsbz");
</SCRIPT>
正規表現のプロパティにアクセスする必要がない場合は、myArray を作成するという別の方法を使用してください。
<SCRIPT type="text/javascript">
myArray = /d(b+)d/g.exec("cdbbdbsbz");
</SCRIPT>
ある文字列から正規表現を組み立てたい場合はさらに別の方法を使用してください。
<SCRIPT type="text/javascript">
myRe = new RegExp ("d(b+)d", "g");
myArray = myRe.exec("cdbbdbsbz");
</SCRIPT>
これらのスクリプトではマッチは成功し、配列を返し、次の表で示されたプロパティが更新されます。
| オブジェクト | プロパティまたはインデックス | 説明 | この例の場合 |
|---|---|---|---|
| myArray | マッチした文字列と、すべての記憶された部分文字列。 | ["dbbd", "bb"] | |
| index | 入力の文字列でのマッチの 0 から始まるインデックス。 | 1 | |
| input | 元の文字列。 | "cdbbdbsbz" | |
| [0] | 最後のマッチした文字列。 | "dbbd" | |
| myRe | lastIndex | 次のマッチが始まるインデックス。(このプロパティは g オプションを用いた正規表現でのみセットされる。グローバルサーチの実行、大文字・小文字の無視、複数行入力の考慮 にて説明する。) | 5 |
| source | パターンのテキスト。正規表現の実行時ではなく作成時に更新される。 | "d(b+)d" |
表 4.3:正規表現の実行結果
この例の 2 つ目の形式で示したように、オブジェクト初期化子を使用して、それを変数に代入することなく作った正規表現を使うことができます。しかしながら、この方法では出現するたびに新しい正規表現として作成されます。このため、変数に代入しないこの形式を使用する場合は、その正規表現のプロパティに後からアクセスすることはできません。例えば、次のようなスクリプトを使用するとします。
<SCRIPT type="text/javascript">
myRe = /d(b+)d/g;
myArray = myRe.exec("cdbbdbsbz");
document.writeln("The value of lastIndex is " + myRe.lastIndex);
</SCRIPT>
このスクリプトは次のように出力します。
The value of lastIndex is 5
しかし、このスクリプトの場合は
<SCRIPT type="text/javascript">
myArray = /d(b+)d/g.exec("cdbbdbsbz");
document.writeln("The value of lastIndex is " + /d(b+)d/g.lastIndex);
</SCRIPT>
次のように出力します。
The value of lastIndex is 0
この 2 つの文で出てくる /d(b+)d/g は別の正規表現オブジェクトであり、そのためにそれぞれの lastIndex プロパティの値は異なるのです。オブジェクト初期化子を用いて作成した正規表現のプロパティにアクセスする必要がある場合は、まずそれを変数に代入するようにしてください。
[編集] 括弧で囲まれた部分文字列のマッチの使用
正規表現パターンに括弧を含めることで、対応するサブマッチが記憶されます。例えば、/a(b)c/ は 'abc' という文字列にマッチし、'b' が記憶されます。この括弧で囲まれた部分文字列のマッチは、配列の要素 [1], ..., [n] を使用して呼び戻すことができます。
括弧で囲まれた部分文字列は何個でも使用できます。返された配列にはその見つかったものすべてが存在します。以下の例では括弧で囲まれた部分文字列の使用法を説明します。
例 1
次のスクリプトでは replace メソッドを使用して文字列中の単語を入れ替えます。置き換えるテキストについては、スクリプトは $1 と $2 を使用して、最初とその次の括弧で囲まれた部分文字列のマッチを示しています。
<script type="text/javascript"> re = /(\w+)\s(\w+)/; str = "John Smith"; newstr = str.replace(re, "$2, $1"); document.write(newstr); </script>
これは "Smith, John" を出力します。
例 2
注意:getInfo 関数では Firefox 以外のほとんどのブラウザでは動作しない () という省略記法を使用して exec メソッドが呼び出されます。
<html>
<script type="text/javascript">
function getInfo(field){
var a = /(\w+)\s(\d+)/(field.value);
window.alert(a[1] + ", your age is " + a[2]);
}
</script>
Enter your first name and your age, and then press Enter.
<form>
<input type="text" name="NameAge" onchange="getInfo(this);">
</form>
</html>
[編集] グローバルサーチの実行、大文字・小文字の無視、複数行入力の考慮
正規表現には、グローバルな検索や大文字・小文字を区別しない検索を可能にする 3 つのオプション的なフラグがあります。グローバルサーチをさせるには g フラグを使用してください。大文字・小文字を区別しない検索をさせるには i フラグを使用してください。複数行の検索をさせるには m フラグを使用してください。これらのフラグは離して使用することもまとめて使用することもできます。順番は問いません。また、正規表現の一部として含めることもできます。
フラグを正規表現に含めるには次のようにしてください。
re = /pattern/flags
re = new RegExp("pattern", ["flags"])
フラグは正規表現の不可分の一部です。後から加えたり取り除いたりはできません。
例えば、re = /\w+\s/g は 1 つ以上の文字とそれに続くスペースを探す正規表現を作成します。また、これは文字列全体を通してこの組み合わせを探します。
<script type="text/javascript"> re = /\w+\s/g; str = "fee fi fo fum"; myArray = str.match(re); document.write(myArray); </script>
この例では ["fee ", "fi ", "fo "] が表示されます。また、この例では次の行
re = /\w+\s/g;
を次の行
re = new RegExp("\\w+\\s", "g");
に置き換えることができます。得られる結果は同じです。
m フラグは複数行の入力文字列を複数の行として扱うようにしているのに用います。m フラグを使用した場合、^ および $ は、文字列全体の先頭または末尾ではなく、入力文字列のどの行の先頭または末尾にもマッチします。
[編集] 例
以下の例では正規表現の使用法をいくつか示します。
[編集] 入力文字列の順序変更
次の例では、正規表現の構造と string.split() および string.replace() の使用法を示します。空白、タブ、1 つのセミコロンで分割された名前(ファーストネームが先)からなる、簡単に整形された入力文字列をきれいにします。最終的に名前の順序を逆転し(ラストネームが先)、リストをソートします。
<script type="text/javascript">
// 名前の文字列は複数のスペースやタブを含む。
// また、ファーストネームとラストネームの間に複数のスペーがあることもある。
var names = "Harry Trump ;Fred Barney; Helen Rigby ; Bill Abel ; Chris Hand ";
var output = new Array(
"---------- Original String<br><br>",
names + "<br><br>");
// 2 つの正規表現パターンと、格納用の配列を用意する。
// 文字列を配列の要素に分割する。
// パターン:ホワイトスペースが存在しうる・セミコロン・ホワイトスペースが存在しうる
var pattern = /\s*;\s*/;
// 上記のパターンで文字列を断片に分割し、
// nameList という配列に断片を格納する。
var nameList = names.split(pattern);
// 新パターン:1 つ以上の文字・1 つ以上のスペース・1 つ以上の文字
// 括弧を用いてパターンの断片を記憶する。
// 記憶しておいた断片は後から参照される。
var pattern = /(\w+)\s+(\w+)/;
// 処理された名前を格納する新しい配列。
var bySurnameList = new Array();
// 名前の配列を表示し、新しい配列にコンマ区切りの名前を
// ラストネーム、ファーストネームの順で格納する。
//
// replace メソッドはパターンにマッチしたものを除去し、
// 記憶しておいた文字列に置き換える。
//「2 番目の記憶しておいた断片とその後に続くコンマとスペース、
// さらにその後に続く 1 番目の記憶しておいた断片」
//
// 変数 $1 および $2 は、パターンにマッチさせた際に
// 記憶しておいた断片を参照する
output.push("---------- After Split by Regular Expression<br>");
var i, len;
for (i = 0, len = nameList.length; i < len; i++)
{
output.push(nameList[i] + "<br>");
bySurnameList[i] = nameList[i].replace(pattern, "$2, $1")
}
// 新しい配列を表示する。
output.push("---------- Names Reversed<br>");
for (i = 0, len = bySurnameList.length; i < len; i++)
{
output.push(bySurnameList[i] + "<br>")
}
// ラストネームについてソートし、ソートした配列を表示する。
bySurnameList.sort();
output.push("---------- Sorted<br>");
for (i = 0, len = bySurnameList.length; i < len; i++)
{
output.push(bySurnameList[i] + "<br>")
}
output.push("---------- End<br>");
document.write(output.join("\n"));
</script>
[編集] 特殊文字を用いた入力の確認
次の例では、ユーザが電話番号を入力します。ユーザが Enter を押すと、スクリプトがその番号の妥当性を確認します。その番号が妥当である(正規表現で指定した文字の連続にマッチしている)場合、スクリプトはユーザへの感謝のメッセージをウィンドウに表示し、その番号を確認します。番号が妥当でない場合は、その電話番号が妥当でないということをユーザに知らせるメッセージをウィンドウに表示します。
正規表現は、0 または 1 つの左括弧 \(?、それに続く 3 つの数字 \d{3}、それに続く 0 または 1 つの右括弧 \)?、それに続き、見つかった場合は記憶しておく 1 つのダッシュ、スラッシュ、または小数点 ([-\/\.])、それに続く 3 つの数字 \d{3}、それに続く記憶しておいた 1 つのダッシュ、スラッシュ、または小数点のマッチ \1、それに続く 4 つの数字 \d{4} を探します。
ユーザが Enter を押したときに発動する Change イベントは RegExp.input の値をセットします。
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
"http://www.w3.org/TR/html4/loose.dtd">
<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}\1\d{4}/;
function testInfo(phoneInput)
{
var OK = re.exec(phoneInput.value);
if (!OK)
{
window.alert(RegExp.input + " 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 press Enter.</p>
<form action="">
<input name="phone" onchange="testInfo(this);">
</form>
</body>
</html>