第1章 JavaScript言語仕様

正規表現

正規表現の概要と使い方

正規表現は、文字列中から特定のパターンを見つけ出すための機構です。
この章では、正規表現を使ったパターンマッチングや、置換、文字列の分割なども学びます。
文字列はダブルクオーテーション( " )などを使って文字列を囲みましたが、正規表現はパターンをスラッシュ( / )で囲みます。

var pat = /abcde/;

これで「abcde」にマッチするRegExpオブジェクトが作成され、変数patに代入されます。正規表現は他の方法でも作成できます。スラッシュで囲んだのと同じように、RegExpを使って正規表現を定義してみましょう。

var pat = new RegEXP("abcde");

RegExpのときはダブルクォーテーションでパターンを囲みます。RegExpは実行時に正規表現を評価するので、変数を使うこともできます。

var x = "cde";
var pat = new RegExp("ab"+x);

以上が正規表現の定義の仕方です。次は、先のような単純なパターンではなく、例えば「a」で始まって、途中は何があるかわからないが最後が「e」という文字列にマッチさせてみましょう。

var pat = /a.*e/;

上記で使っているドット( . )は改行以外の1文字を表し、アスタリスク( * )はその任意の文字の0回以上の繰り返しを意味しています。このように、正規表現において特殊な働きを持った文字をメタ文字と呼びます。

match()

match()メソッドは、指定した文字・正規表現にマッチする文字列を返します。

構文
str.match( パターン );

それでは、match()を使って文字列からパターンを検索してみましょう。
次の例では、「ABCDEFG」という文字列に、Aから始まってEで終わるようなパターンがあるかを調べています。

var pat		= /A.*E/;
"ABCDEFG".match( pat )[0];
"ABCDE"

出力結果の通り、「ABCDE」がマッチしました。match()はマッチした値を配列で返しますが、特定の要素だけ欲しい場合、上記のようにmatch()の後でインデックスを指定することで取得できます。

上記のように正規表現を変数に代入せず、直接match()の引数として渡すこともできます。

var found	= str.match( /a.*e/ );

後で詳しく説明しますが、正規表現にはいくつかのオプションが用意されています。例えば、複数マッチする g オプションを使うと、マッチしたすべての文字が配列で返されます。次の例では、任意の1文字にマッチするドット( . )と、複数マッチする g オプションを使い、マッチする文字がなくなるまで繰り返しマッチングを行っています。

"ABCDEFG".match( /./g );

["A", "B", "C", "D", "E", "F", "G"]

正規表現のメタ文字

正規表現で特に重要なのがメタ文字です。正規表現のメタ文字はその文字自体を表すものではありません。メタ文字を使うと、「行頭にあるパターンだけを探す」、「英数字を探す」、「大文字または小文字で始まるパターンだけを探す」など、さまざまな方法で検索パターンを指定することができます。

文字クラス

ブラケット( [] )で囲んだ1つ以上の文字は文字の集合を表し、文字クラスと呼ばれます。文字クラスをパターンに使うと、文字クラスに含まれる文字のどれか1文字に当てはまる文字があればマッチします。

// a b c d e のどれか1文字を表現します
/[abcde]/

文字クラスの中では、ドット( . )やアスタリスク( * )といったメタ文字も普通のリテラルとして扱われるので、エスケープ不要です。

// ドット1文字にマッチします
/[.]/

文字や数字の範囲を示したいときはハイフン( - )が使えます。

// 0から9の数字1文字とマッチ
/[0-9]/

// 大文字・小文字を含めた全ての英字1文字とマッチ
/[a-zA-Z]/ 

キャラット( ^ )は否定を意味します。例えば、下記は1、2、3のいずれでもない文字で始まるパターンにマッチします。

/[^123]/

文字集合の中に、ハイフン( - )などメタ文字そのものを含めたい場合は、その前にバックスラッシュ( / )をおいてエスケープします。

// zの後のハイフンは特殊文字ではなく通常の文字として使われます
/[a-z\-]/
正規表現の文字クラス
メタ文字説明
[X]

ブラケット( [ ] )の中の任意の1文字にマッチします。

文字の間にハイフン( - )を挟み、文字列の範囲を表すことができます。たとえば、[12345]の様に規則的に連続した文字列は、[1-5] と表記できます。[abcd] は [a-d] と表記できます。

下記はgオプションを使ってマッチする文字がなくなるまで繰り返しています。

var str	= "A-B-C";
str.match( /[a-zA-Z0-9]/g );

["A", "B", "C"]

[^X]

ブラケット( [ ] )の中に含まれない任意の1文字にマッチします。
それ以外は[X]と同じです。

var str	= "A-B-C";
str.match( /[^a-zA-Z0-9]/g );

["-", "-"]

\w

アンダースコアを含む英数字の1文字にマッチします。
[a-zA-Z_0-9] と同じです。

var str	= "You talkin' to me?";
str.match( /\w/g );

["Y", "o", "u", "t", "a", "l", "k", "i", "n", "t", "o", "m", "e"]

\W

アンダースコアを含む英数字以外の1文字にマッチします。
[^a-zA-Z_0-9] と同じです。

var str	= "You talkin' to me?";
str.match( /\W/g );

[" ", "'", " ", " ", "?"]

\d

数字の1文字にマッチします。
[0-9] と同じです。

var str	= "The Magnificent 7";
str.match( /\d/g );

["7"]

\D

数字以外の1文字にマッチします。
[^0-9] と同じです。

var str	= "The Magnificent 7";
str.match( /\D/g );

["T", "h", "e", " ", "M", "a", "g", "n", "i", "f", "i", "c", "e", "n", "t", " "]

\s

空白文字にマッチします。
空白文字にはスペース、タブ、改行などが含まれます。

var str	= "The Magnificent 7";
str.match( /\s/g );

[" ", " "]

\S

空白文字以外にマッチします。

var str	= "The Magnificent 7";
str.match( /\S/g );

["T", "h", "e", "M", "a", "g", "n", "i", "f", "i", "c", "e", "n", "t", "7"]

[\b]

リテラルバックスペース(U+0008)にマッチします。
\b と混同しないように、ブラケットで囲みます。

選択・グループ化・参照

正規表現では、あとで使えるようにマッチした文字列を記録したり、複数のパターンのどちらかにマッチさせることができます。

正規表現の選択・グループ化・参照
正規表現の文字クラス
メタ文字説明
(X)

カッコ( () )は、囲んだパターンにマッチした場合、その文字列を記録します。カッコで囲んだグループの左から順に、RegExp オブジェクトを使って RegExp.$1、RegExp.$2、RegExp.$3...という表記で参照できます。これを後方参照といいます。

var str	= "After all, tomorrow is another day.";
// 先頭の単語にマッチ
str.match( /^(\w+)/ ); 

RegExp.$1;

"After"

後方参照は replace() の第2引数にも使えます。replace()については後程紹介します。

var str	= "after all, tomorrow is another day.";
// 行頭の単語を大文字に変換
console.log( str.replace( /^(\w)/, RegExp.$1.toUpperCase() ) ); 

"After all, tomorrow is another day."

replace() 内であれば RegExp を省略できます。

var str	= "after all, tomorrow is another day.";
// 行頭の単語にを大文字に変換
str.replace( /^(\w)/, "($1)" ); 

"(a)fter all, tomorrow is another day."

(?:X)

(X)と同じでカッコ内のパターンにマッチしますが、後方参照はできません。

var str	= "After all, tomorrow is another day.";
// 先頭の単語にマッチ
str.match( /^(?:\w+)/ ); 

RegExp.$1;

""

X|Y

パイプ( | )の前後あるどちらかの正規表現にマッチします。X|Y であれば X、Y のいずれか1つの文字にマッチします。
下記では g オプションを使ってどちらの選択もマッチするようにしています。

var str	= "Don’t think, feel.";

str.match( /think|feel/g ); 

["think", "feel"]

選択一致パターンとグループ化の組み合わせ

選択一致パターンのパイプ( | )は、文字列のグループ化と組み合わせて使うと効果的です。たとえば、main か sub という単語を探したい場合は、次のように書くことができます。

/main|sub/

ただ、グループ化すると自動的に後方参照用に記憶されるので、多少ではありますが処理が遅くなります。これを避けるには、後方参照を行わないグループ化の構文( ?:... )を使います。

// マッチした文字列は記録されません
/(?:main|sub)/

量指定子

量指定子は、その直前の要素が何回マッチするかを指定します。たとえば、a* は0個以上の a にマッチします。

正規表現の量指定子
メタ文字説明
*直前の文字の 0 回以上の繰り返しにマッチします。
+直前の文字の 1 回以上の繰り返しにマッチします。
?直前の文字の 0 個か 1個にマッチします。
.改行文字( ¥n )を除く任意の 1 文字にマッチします。
{m, n}

直前の文字が m 回以上、n 回以下の繰り返しにマッチします。

{m} m 回の繰り返しにマッチ
{m,} m 回以上の繰り返しにマッチ
{m,n} m 回以上、n 回以下の繰り返しにマッチ

a が少なくとも1回、最大でも3回繰り返すパターンを検索

/a{1,3}/

a が3回繰り返すパターンを検索

/a{3}/

a が少なくとも1回以上続くパターンを検索

/a{1,}/

貪欲量指定子

量指定子は可能な限り長いマッチを行います。次の例は、空白と任意の1文字の後に eed が続く単語を探したい場合の間違った例です。

var str	= "The need for speed!";

str.match( / .+eed/ )[0]; 

"need for speed2

needにマッチすることを期待していましたが、.*は need for speed までマッチしてしまいます。量指定子は許された最大数マッチしようとするので、.* は1つ目の候補の need を過ぎて2つ目の候補の speed までマッチしてしまいました。

最短マッチを行いたい場合は、量指定子の後にクエスチョン( ? )を使います。

str.match( / .+?eed/ )[0]; 

" need"

基本的な繰り返しパターン検索
// 0個、または1個以上の A にマッチ
/A?/

// 0個以上の A にマッチ
/A*/

// 1個以上の A にマッチ
/A+/ 

// 0個、または1個以上の任意の文字にマッチ
/.?/

// 0個以上の任意の文字にマッチ 
/.*/ 

// 1個以上の任意の文字にマッチ
/.+/ 

アンカー

アンカーは、行頭や行末など、文字列中の位置にマッチします。行頭を表す ^ と、行末を表す $はおぼえておいたほうがよいでしょう。

正規表現のアンカー
メタ文字説明
^

先頭にマッチします。複数行検索になっている場合はすべての行の先頭にもマッチします。

var str	= "as soon as possible";
// 先頭の as しかマッチしない
str.match( /^as/g ); 

["as"]

ブラケット( [] )で囲まれた文字集合の中で使われたときは、行頭ではなく否定のメタ文字として使われます。

$

末尾にマッチします。複数行検索になっている場合はすべての行の末尾にもマッチします。

var str	= "as soon as possible";
// 末尾の単語しかマッチし
str.match( /\w+$/g ); 

["possible"]

\b

単語の区切りにマッチします。単語に含まれるのは\w(英数字とアンダースコア)のみで、それ以外が単語の区切りと判断されます。

var str	= "The need for speed!";
str.match( /\bneed/ )[0]; 

"need"

\b はマッチした文字に含まれないことに注意してください。\b にマッチした空白はマッチした文字に含まれません。

\B単語の区切り以外の文字にマッチします。それ以外は \b と同じです。
X(?=Y)

X の後に Y が続く場合のみ X にマッチします。

var str	= "I'm the king of the world!";

str.match( /.*(?=of)/ )[0]; 

"I'm the king "

X(?!Y)

X の後に Y が続かない場合のみ X にマッチします。

var str	= "I'm the king of the world!";

// 単語1文字以上と、単語以外にマッチ
str.match( /\w+(?!\w)/ )[0];

"I"

正規表現のエスケープシーケンス

メタ文字をエスケープする

バックスラッシュ( \ )を使って後続の文字をエスケープすると、メタ文字をリテラルとしてマッチさせることができます。

たとえば、ドメイン名には、メタ文字のドット( . )が含まれますが、エスケープを使わずにドットを使うと任意の1文字にマッチしてしまいます。

var str	= "rfs_jp";
str.match( /rfs.jp/ )[0];

"rfs_jp"

エスケープすることで、ドット以外の文字にはマッチしなくなります。

str.match( /rfs\.jp/ );

null

正規表現では以下のエスケープシーケンスが使えます。

エスケープシーケンスの一覧
メタ文字説明
\bバックスペース
\t水平タブ
\v垂直タブ
\n改行
\r行頭復帰
\f改ページ
\'シングルクオーテーション
\"ダブルクオーテーション
バックスラッシュ
\0NULL文字
\cXX で指定した制御文字にマッチします。X には A - Z のいずれかの 1 文字が入ります。
例えば、/\cM/ は、文字列中の control-M にマッチします。
\xXX2桁の16進数からなる文字にマッチします。正規表現で ASCII コードを表現できます。
\uXXXX4桁の16進数からなる文字にマッチします。正規表現で Unicodeを表現できます。

正規表現を扱うメソッド

replace()

replace()メソッドは、パターンにマッチした文字列を指定した文字で置き換えて、その結果の文字列を返します。指定した文字列を任意の文字列で変更することを置換と言います。

構文

str.replace( パターン, 置換文字 )

replace()の第1引数には、パターンになる文字列・正規表現を指定します。マッチした文字列は第1引数の置換文字と置き換えられます。
パターンには下記のオプションを指定できます。

オプション効果
g繰り返してマッチ。マッチする文字列がなくなるまで繰り返される。
i英字の大文字、小文字を区別しない。
m複数行に対応したマッチ。複数行で行頭( ^ )および行末( $ )が有効になる。
// 繰り返しマッチ、aからzまでの文字すべてにマッチします。
var str	= "abcDEfg";
str.match( /[a-z]/g );

["a", "b", "c", "f", "g"]

// aからzまでの大文字、小文字の文字すべてにマッチします。
var str	= "abcDEfg";
str.match( /[a-z]/ig );

["a", "b", "c", "D", "E", "f", "g"]

// 行頭の T にマッチ、複数行に対応します(getElementById でテキストエリアの文字を取得している前提)。
var str = document.getElementById("text");
str.match( /^T/m );

replace()の第2引数には、第1引数でマッチした文字列を置き換える文字列、もしくは実行する関数を指定します。

var str	= "after all, tomorrow is another day.";
// 行頭の単語にを大文字に変換
console.log( str.replace( /^(\w)/, RegExp.$1.toUpperCase() ) ); 

After all, tomorrow is another day.

replace()は、パターンにマッチした文字列を置換文字で置き換えた新しい文字列を返します。

search()

search() メソッドは、は指定した文字・正規表現にマッチする文字列を返します。

構文

str.search( パターン );

search() は、引数として渡したパターンにマッチマッチした場所のインデックスを返します。マッチしなかった場合は -1 を返します。

var str		= "abcDEFG";
str.search( /[A-Z]/ );

3

split()

split() メソッドは、指定した区切り文字で文字列を分割し、配列にして返します。

構文

str.split([区切り[, リミット]])

splitの第1引数には、区切り文字を指定します。区切り文字には正規表現も使えます。区切り文字に空文字を指定、もしくは省略した場合、文字ごとに分割されます。

第2引数には、分割数の制限を指定します。

splitの返却値は、分割後の配列です。

次の例では、文字列をカンマで分割しています。

"One,Two,Three".split(",");

["One", "Two", "Three"]

文字列を空白で分割します。

"One Two Three".split(/\s/);

["One", "Two", "Three"]

空白で分割し、返す値を2つまでに制限しています。

"One Two Three".split(/\s/, 2);

["One", "Two"]

test()

test() メソッドは、パターンにマッチしたかどうかの結果を真理値で返します。マッチしたら true、マッチしなければ false です。文字列がパターンにマッチするかを判別したい場合は test()、マッチした文字列が必要な際は match() を使います。

構文

RegExpオブジェクト.test( 文字列 )

次の例では、test()で指定した文字列に小文字の英字が含まれているかを評価します。

/[a-z]/.test("ABC");

false

/[a-z]/.test("abc");

true

正規表現のテクニック集

文字列の末尾が改行かをチェックする

改行コードはオペレーティングシステムによって違います。UNIX 系 OS の改行は \n、ウインドウズは \r\n 、マッキントッシュは \r が使われています。次のコードはどの環境の改行コードにもマッチします。

/[\r\n]/

ワード境界の罠

空白文字の集合を表す \s 、ワードの集合を現す \w 、ワードの境界を表す \b の組み合わせには十分な注意が必要です。

次の正規表現は、後ろに空白文字が続くワードを拾おうとしています。一見、まともな正規表現に見えますね。

/(\w+)\s+/;

「It is enjoy」というような文字列でしたら問題ないのですが、「It's enjoy」というようにワード以外を含んだ文字列にはマッチしません。「It's」のシングルクォートの箇所がワードの区切りとなり、空白文字の直前にある「s」しか取り出せません。正解は次のようになります。

/(\S+)\s+/;

このように、なるべく、\s の次には \S を続けるように注意しましょう。

マッチしないパターンを使わない

マッチしないパターンは、マッチするパターンより処理時間が何十倍もかかることがあります。これはマッチするパターンはマッチした時点でその処理を終わらせられますが、マッチしない場合は様々なケースでマッチしないことを確認する必要があるためです。

行末で分割する

行末は、OS(Unix、Windows など)により ¥r¥n や ¥r、¥n などの違いがあります。正規表現を使えば、どのOSでも改行毎の処理ができます。

var str		= 'One\nTwo\nThree';
str.split(/\r\n|\r|\n/);

["One", "Two", "Three"]

関連記事