正規表現

RegExpオブジェクト

RegExpオブジェクトは、正規表現のためのオブジェクトです。

オブジェクトの生成

正規表現リテラル (regular expression literal)

文字列をスラッシュで囲んで記述することで、正規表現のパターンを指定する正規表現リテラルとみなされます。たとえば、

var pattern = /[0-9]+/g;

とすると、patternはRegExpオブジェクトとして生成されます。

コンストラクタ

通常は正規表現リテラルでも代用できますが、正規表現のパターンを動的に生成する必要があるときには、コンストラクタにより明示的に生成します。

new RegExp( pattern [, flags ] );

このオブジェクトを生成するには、

var pattern = new RegExp( '[0-9]+', 'g' );

のようにします。このコードにより生成されるRegExpオブジェクトは、前述の正規表現リテラルと同一です。

new RegExp( 'a' ); // /a/
new RegExp( '' );  // /(?:)/

new RegExp( '[0-9]+', 'g' ); // /[0-9]+/g
フラグ (flags)

コンストラクタのflags引数には、次のいずれかを指定できます。

文字 意味
i 大文字と小文字を区別しない
g グローバル検索 (グローバルマッチ)

一致するもの、すべてを検索する。

m マルチラインモード

「^」は文字列と行の先頭、「$」は文字列と行の末尾に一致させる。

Perlなどのマッチモードにあるsフラグ (シングルラインモード) はサポートされないため、複数行を処理できません

プロパティ

プロパティ 内容
global 「g」属性を持つかどうか
ignoreCase 「i」属性を持つかどうか
multiline 「m」属性を持つかどうか
lastIndex 最後にマッチした文字の位置
source 正規表現オブジェクトのソーステキスト
Properties - RegExp - JavaScript | MDN

メソッド

メソッド 説明
exec 文字列のパラメータでマッチングを行う
test 文字列にパターンが含まれているか調べる
compile 正規表現をコンパイルする。これは基本的にRegExpコンストラクタと同じ [非推奨]
Methods - RegExp - JavaScript | MDN

RegExp.exec()

通常のパターンマッチングでは行えないような複雑な処理をするには、exec()メソッドを使用します。とくにグローバルマッチで部分正規表現を取得するには、このメソッドでなければなりません。

regexObj.exec( str );
exec - JavaScript | MDN

たとえば次のコードを実行した場合、

var text = 'Hello! world';
var pattern = /l+/g;

var match;
while( match = pattern.exec( text ) )
{
    // @todo
}

exec()の結果は、

ループ回数 match match.index match.input pattern.lastIndex
1回目 ["ll"] 2 "Hello! world" 4
2回目 ["l"] 10 "Hello! world" 11
3回目 null --- 0

のように返されます。このときパターンをグローバルマッチとせず/l+/とすると、

ループ回数 match match.index match.input pattern.lastIndex
1回目 ["ll"] 2 "Hello! world" 0
2回目 ["ll"] 2 "Hello! world" 0
3回目 ["ll"] 2 "Hello! world" 0
4回目

のように、1回目と同じ結果が返され続けます。

lastIndexプロパティ

lastIndexプロパティはマッチを開始する位置を表し、その値はマッチした場合のみ進みます。

  マッチした マッチしなかった
lastIndexの位置が文字列の末尾より前 マッチした文字列の数だけ加算 変化なし
lastIndexの位置が文字列の末尾 マッチした文字列の数だけ加算 0にリセット
lastIndexの位置が文字列の末尾より後 (決してマッチしない) 0にリセット

lastIndexの値はString.match()やString.search()によっても変化しますが、これらのメソッドへは影響しません。

var text = '123';
var pattern = /[0-9]/g;

pattern.lastIndex = 1;
console.log( text.match( pattern ) ); // [ "1", "2", "3" ]
console.log( pattern.lastIndex );     // 0

pattern.lastIndex = 1;
console.log( text.search( pattern ) ); // 0
console.log( pattern.lastIndex );      // 1
マッチ位置の制御

lastIndexプロパティに値を設定することで、マッチさせる位置を制御できます。RegExp.lastIndex - JavaScript | MDN

var text = '12345';
var pattern = /[0-9]/g;

alert( pattern.exec( text ) ); // 1
alert( pattern.exec( text ) ); // 2
alert( pattern.exec( text ) ); // 3

pattern.lastIndex = 0;

alert( pattern.exec( text ) ); // 1
alert( pattern.exec( text ) ); // 2

pattern.lastIndex = 10;

alert( pattern.exec( text ) ); // null

RegExp.test()

regexObj.test( str );
RegExp.test - JavaScript | MDN

正規表現がstrにマッチしたならば、trueが返されます。

new RegExp( '[0-9]' ).test( 'abc' ); // false
new RegExp( '[0-9]' ).test( '123' ); // true

test()はexec()同様、グローバルマッチで複数呼び出すと、マッチした場合にはlastIndexプロパティが進みます。

var text = '123';
var pattern = /[0-9]/g;

console.log( pattern.test( text ) ); // true
console.log( pattern.test( text ) ); // true
console.log( pattern.test( text ) ); // true
console.log( pattern.test( text ) ); // false (文字列の末尾でマッチしないと、lastIndexは0にリセットされる)
console.log( pattern.test( text ) ); // true (lastIndexがリセットされたことにより、再びマッチする)

このことからexec()と混在して用いると、予期せぬ結果となることがあります。

var text = '123';
var pattern = /[0-9]/g;

console.log( pattern.test( text ) ); // true
// ここでlastIndexは1となっている

console.log( pattern.exec( text ) ); // 2 (2文字目からマッチしている)
console.log( pattern.exec( text ) ); // 3
console.log( pattern.exec( text ) ); // null

よって正規表現オブジェクトを使い回す場合は、明示的にlastIndexをリセットするようにします。

var text = '123';
var pattern = /[0-9]/g;

console.log( pattern.test( text ) ); // true

pattern.lastIndex = 0; // lastIndexをリセットする
console.log( pattern.exec( text ) ); // 1 (1文字目からマッチしている)
console.log( pattern.exec( text ) ); // 2
console.log( pattern.exec( text ) ); // 3

文字クラス

指定文字のいずれかにマッチする、文字クラスがサポートされます。

略記法

文字クラスの略記法もサポートされます。

メタ文字を文字列リテラルで記述するときは、エスケープが必要です。

メタ文字 ※1 意味 別表記
\d 任意の数字 (Decimal digit) [0-9]
\w 任意の単語文字 (Word) [a-zA-Z0-9_]
\s 任意のUnicode空白文字 (White space) [ \f\n\r\t\v\u00a0\u1680\u180e\u2000-\u200a\u2028\u2029\u202f\u205f\u3000] ※2
Using special characters - Regular Expressions - JavaScript | MDN

※1 メタ文字を大文字にすると、それを否定した意味になります。
※2 幅ゼロの空白文字\u200B\uFEFFは含まれません。

メタ文字に不足する文字がある場合には、全体を[]で囲み文字を追加します。

/[\da-z]/

サポートされない機能

Perlの正規表現と比較して、次の機能が使用できません。

  • フラグ
    • sフラグ (シングルライン モード)
    • xフラグ (フリーフォーマット モード)
  • エスケープシーケンスの一部
    • \a\e\l\u\L\U\E\Q\A\Z\z\G
  • (?拡張構文の一部

記述上の注意

スラッシュのエスケープ

正規表現リテラルにスラッシュを記述するには、それをエスケープする必要があります。

/\//.test( 'SAMPLE/' )

同様の処理でも、RegExpのコンストラクタで記述する場合には、エスケープは不要です。

new RegExp( '/' ).test( 'SAMPLE/' )

メタ文字のエスケープ

文字列リテラル正規表現リテラルでは、文字列中のバックスラッシュの扱いが異なります。よってこの2つを書き換える際には、注意が必要です。

たとえば「?」という記号にマッチさせる場合を考えます。これは量指定子のメタ文字であるため、

/\?/

のように、正規表現ではこれをバックスラッシュでエスケープする必要があります。一方でこの表現をそのまま文字列リテラルに当てはめて、

new RegExp( '\?' )

とすると、「SyntaxError: invalid quantifier」の例外が発生します。これは「\?」というエスケープシーケンスが存在しないため「?」と解釈され、結果として不正な正規表現となっているためです。

このとき文字列リテラルにバックスラッシュを記述するには「\\」とすることを踏まえると、正しくは

new RegExp( '\\?' )

とすべきことがわかります。

バックスラッシュへのマッチ

文字列リテラルにバックスラッシュを記述するにはエスケープが必要であり、かつバックスラッシュにマッチさせるためにもエスケープが必要であることから、バックスラッシュにマッチさせるためには、

new RegExp( '\\\\' )

のように記述します。一方で正規表現リテラルで記述するときはバックスラッシュのエスケープは不要なため、

/\\/

とします。≫PHPの正規表現でバックスラッシュにマッチさせる方法

参考

参考書

JavaScriptのドキュメントから検索