JavaScript/RegExp
- JavaScript > RegExpオブジェクト
RegExp
編集RegExpオブジェクトは正規表現を扱うための標準組み込みオブジェクトである。
正規表現とは、文字列の検索や置換に用いられる文字規則の表現である。 JavaScriptは高度な正規表現の機能を備えている。
正規表現は、Unixのgrepやsedで文字列の検索の機能として採用される。その後awkという言語がそれに続き、Perlがその文法を受けついだ。 正規表現は言語ごとに機能の違いがあり、言語間の移植にあたっては注意を払う必要がある。
次にHTMLの要素名を取得する例を示す。要素名は"<"の文字に続く「先頭が英字でそれに0文字以上の英数字が続く文字列」である。これを正規表現で検索するには、以下のように記述する。
/<[a-zA-Z][a-zA-Z0-9]*/
これでHTMLの要素名を取得するには完全ではないのだが、とりあえずその点を飛ばして解説をする。 JavaScriptでは、正規表現をスラッシュ"/"の間に記述をする。 この規則の場合は小なり記号"<"に続き「 先頭が英字 で それに続き英数字が0文字以上(*)続く」ものがが要素名であるとすることでタグを検索している。
スラッシュで囲う表記法はJavaScriptで用意されている正規表現のリテラル表記で、実際には次の3つは意味的に等価である。
const regexp = /ab/; const regexp = new RegExp( "ab" ); const regexp = new RegExp( /ab/ );
正規表現の作り方
編集正規表現には、前述した「*」以外にも様々な特殊記号が存在している。 まずはそれらを一覧する。
クエスチョン『?』
編集直前のパターンが存在しなくてもいいような場合を表す。
/html?/
はhtmlとhtmいずれにもマッチする。
プラス『*』
編集直前のパターンを0回以上繰り返した文字列を表す。
"Yaho*
"と表記すると、"Yahoo"や"Yahooooooo"、"Yah"にマッチする。
プラス『+』
編集直前のパターンを1回以上繰り返した文字列を返す。
「Go+gle
」と表記すると"Google"、"Goooooogle"でもマッチするが"Ggle"ではマッチしない点がアスタリスクでの表記と異なる。
中括弧『{n}』
編集n回繰り返したパターンを表す。 "{n,m}"ではn回以上、m回以下にマッチし"{n,}"でn回以上にマッチする。
例を挙げる。次の例は"Google"や"Goooooogle"にはマッチするが、"Gogle"にはマッチしない。
/Go{2,}gle/;
"*", "+", "?", "{n}", "{n,}", "{n,m}" 等のパターンのマッチ回数を表す文字を量指定子と言う。
ドット『.』
編集改行以外の任意の1文字を表す。
ハット記号『^』
編集文頭を表す。
ドル記号『$』
編集文末を表す。
フェンス『|』
編集指定したもののいずれかを表す。
括弧『(?:)』
編集括弧の中の文字列を表すが、後方参照のグループに含まれない。フェンスと組み合わせて次のように使用できる。
/(?:りんご|ゴリラ|ラッパ)/
括弧『()』
編集括弧の中の文字列を表し、後方参照のグループに含める
ブラケット『[]』
編集囲った範囲の文字のいずれか1文字を表す。 つまり次の2文は同じ意味を持つ。
/(?:0|1|2|3|4|5|6|7|8|9)/; /[0123456789]/;
ブラケット『[A-Z]』
編集A~Zまでの文字列のいずれかを表す。
同様に[a-z]
では小文字のa~zを、[0-9]
では数字の0~9のいずれかを表す。
ちなみに、ブラケットとハイフンの組み合わせは複数記述できるため、
[0-9a-zA-Z_]
とすれば、数字かアルファベット、アンダーバーのいずれかにマッチする。
否定演算子『^』
編集ブラケットの中で使用し、指定した文字以外を意味する。
[^A-Z]
では大文字のアルファベット以外を意味する。
半角スペース『 』
編集1文字分のスペースを表す。
バックスラッシュ『\』
編集直後の1文字の特殊文字をエスケープする。\|
とすると"|"という文字を表す
その他の特殊文字
編集JavaScriptでは次のような特殊文字も用意している。 これらはPerlで拡張された正規表現から受け継いでいる。
特殊文字 | 結果 |
---|---|
\t | 1文字分のタブを表す。 |
\f | フォームフィールドを表す。 |
\r | キャリッジリターンを表す。 |
\n | 改行記号を表す。 |
[\b] | バックスペースを表す。 |
\d | 1文字分の数字を表す。"[0-9]"に等しい |
\D | 数字以外の1文字を表す。"[^\d]"に等しい |
\w | 数字とアルファベットかアンダースコア(_)のいずれかを表す。"[0-9a-zA-Z_] "と等しい。 |
\W | \w以外の1文字を表す。"[^\w] "と等しい。 |
\s | 空白改行を表す。"[\t\n\v\f\r \u00a0\u2000-\u200b\u2028-\u3000]"と等しい。 |
\S | \s以外の1文字を表す。"[^\s]"と等しい。 |
\b | 単語の境界を表す。 |
\B | 単語がそこで終わらないことを意味する。 |
\b,\B のみ新しい概念なので解説する。
/alpha\b/;
の場合、"alpha beta"にはマッチするが、"alphabet"にはマッチしない。 "\B"はその逆で"alphabet"にはマッチするが、"alpha beta"にはマッチしない。
オプション
編集文字列"abrakadabra"に2箇所存在する"ab"の検索を考える。オプションを指定せずに検索を行うと最初の"ab"にはマッチするが、次の"ab"にマッチをしない。 全てにマッチするには、正規表現のオプションを利用して次のように表記する。
/ab/g
最後についているgがオプションで、globalを表す。実行結果は次のようになる。
const s = "abrakadabra"; s = s.replace( /ab/g, '**' ); // **rakad**ra
その他にも、さまざまなオプションが存在する。組み合わせて利用する場合には連続して記述をすればよい。
/ab/g; /ab/igm; // i,g,mの3オプション new RegExp( "ab", "i" ); new RegExp( "ab", "gm" );
それぞれのオプションの意味は次の通りである。
オプション | 説明 |
---|---|
g | 全文検索を行う。 |
i | 大文字、小文字の区別無くマッチする。 |
m | 行頭、行末のマッチに対応する。 |
最長マッチ
編集基本的に、正規表現はマッチする限り、一番長い組み合わせを取得しようとする。これを最長マッチ(貪欲なマッチ)と言う。 これは「\w+」としてマッチする限り文字を拾い続ければ単語が取得できる事からも自然な仕様と言える。しかし、「<.+>」の様に記述した場合には、HTMLのタグ一つではなく、文中の一番長い"<"と">"の間を取得する。 最も短い組み合わせを取得するには、量指定子(quantifier)に続いて"?"を付ける。これを最短マッチと言う。
後方参照
編集正規表現中で括弧「()」を使用して囲った文字列は、後方参照の対象となる。 マッチした文字列は保存され、後に取得が可能である。
// HTML中のタグを取得する const s="bbb<em>aaaa</em>ccc"; const m = s.match(/<.+?>(.*?)<\/.+?>/); m[0]; // <em>aaaa</em> が返る。 m[1]; // aaaa が返る。
1、2、3とマッチした文字列が括弧の順に格納されている。 インデックスの0はマッチした文字列全体が格納されている。
後方参照の必要がない場合には、括弧の内部に"?:"を挿入して次の様に記述する。
/(?:abc)+/;
$1~$9
編集正規表現を実行して、マッチした結果を返す。
// i,b,big等のタグをemタグへ変換する s.replace( /(<\/?)(?:i|b|s|small|strike|big|tt)/i, '$1em' ); // $1で参照結果("<"か"</")を呼び出し
先読み
編集Disjunction一致部分は結果に含まれない。
パターン | 説明 |
---|---|
(?=Disjunction) | 先読み言明(Lookahead assertions)。パターンDisjunctionが後に続くことが必要。 |
(?!Disjunction) | 否定先読み言明。パターンDisjunctionが後に続かないことが必要。 |
静的プロパティ
編集RegExp.$&
編集最後に一致した文字列を返すプロパティ。
- 例
const str = "JavaScript is awesome!"; const regex = /is/; regex.test(str); console.log(RegExp.$&); // "is"
RegExp.$'
編集最後に一致した文字列の後にある文字列を返すプロパティ。
- 例
const str = "JavaScript is awesome!"; const regex = /is/; regex.test(str); console.log(RegExp.$'); // " awesome!"
RegExp.$+
編集最後のキャプチャグループに一致する部分を返すプロパティ。
- 例
const str = "123-456-7890"; const regex = /(\d+)-(\d+)-(\d+)/; regex.test(str); console.log(RegExp.$+); // "7890"
RegExp.$1
編集最初のキャプチャグループに一致する部分を返すプロパティ。
- 例
const str = "123-456-7890"; const regex = /(\d+)-(\d+)-(\d+)/; regex.test(str); console.log(RegExp.$1); // "123"
RegExp.$2
編集2番目のキャプチャグループに一致する部分を返すプロパティ。
- 例
const str = "123-456-7890"; const regex = /(\d+)-(\d+)-(\d+)/; regex.test(str); console.log(RegExp.$2); // "456"
RegExp.$3
編集3番目のキャプチャグループに一致する部分を返すプロパティ。
- 例
const str = "123-456-7890"; const regex = /(\d+)-(\d+)-(\d+)/; regex.test(str); console.log(RegExp.$3); // "7890"
RegExp.$4
編集4番目のキャプチャグループに一致した文字列を返します。
- 例
const str = "Name: John, Age: 30, City: Tokyo"; const regex = /Name: (\w+), Age: (\d+), City: (\w+)/; regex.test(str); console.log(RegExp.$4); // undefined(4番目のキャプチャグループがないため)
RegExp.$5
編集5番目のキャプチャグループに一致した文字列を返します。
- 例
const str = "Group1: A, Group2: B, Group3: C"; const regex = /Group1: (\w), Group2: (\w), Group3: (\w)/; regex.test(str); console.log(RegExp.$5); // undefined(5番目のキャプチャグループがないため)
RegExp.$6
編集6番目のキャプチャグループに一致した文字列を返します。
- 例
const regex = /(\w+)-(\w+)-(\w+)-(\w+)-(\w+)-(\w+)/; const str = "a-b-c-d-e-f"; regex.test(str); console.log(RegExp.$6); // "f"
RegExp.$7
編集7番目のキャプチャグループに一致した文字列を返します。
- 例
const regex = /(\w+)-(\w+)-(\w+)-(\w+)-(\w+)-(\w+)-(\w+)/; const str = "a-b-c-d-e-f-g"; regex.test(str); console.log(RegExp.$7); // "g"
RegExp.$8
編集8番目のキャプチャグループに一致した文字列を返します。
- 例
const regex = /(\w+)-(\w+)-(\w+)-(\w+)-(\w+)-(\w+)-(\w+)-(\w+)/; const str = "a-b-c-d-e-f-g-h"; regex.test(str); console.log(RegExp.$8); // "h"
RegExp.$9
編集9番目のキャプチャグループに一致した文字列を返します。
- 例
const regex = /(\w+)-(\w+)-(\w+)-(\w+)-(\w+)-(\w+)-(\w+)-(\w+)-(\w+)/; const str = "a-b-c-d-e-f-g-h-i"; regex.test(str); console.log(RegExp.$9); // "i"
RegExp.$_
編集最後に検索された文字列を返すプロパティ。
- 例
const str = "JavaScript is awesome!"; const regex = /is/; regex.test(str); console.log(RegExp.$_); // "JavaScript is awesome!"
RegExp.$`
編集最後に一致した文字列の前にある文字列を返すプロパティ。
- 例
const str = "JavaScript is awesome!"; const regex = /is/; regex.test(str); console.log(RegExp.$`); // "JavaScript "
RegExp.input
編集最後に検索された文字列を返します。これは RegExp.$_
と同じです。
- 例
const str = "JavaScript is awesome!"; const regex = /is/; regex.test(str); console.log(RegExp.input); // "JavaScript is awesome!"
RegExp.lastMatch
編集最後に一致した文字列を返します。これは RegExp.$&
と同じです。
- 例
const str = "JavaScript is awesome!"; const regex = /is/; regex.test(str); console.log(RegExp.lastMatch); // "is"
RegExp.lastParen
編集最後のキャプチャグループに一致した文字列を返します。これは RegExp.$+
と同じです。
- 例
const str = "123-456-7890"; const regex = /(\d+)-(\d+)-(\d+)/; regex.test(str); console.log(RegExp.lastParen); // "7890"
RegExp.leftContext
編集最後に一致した文字列の前にある部分文字列を返します。これは RegExp.$
` と同じです。
- 例
const str = "JavaScript is awesome!"; const regex = /is/; regex.test(str); console.log(RegExp.leftContext); // "JavaScript "
RegExp.rightContext
編集最後に一致した文字列の後にある部分文字列を返します。これは RegExp.$'
と同じです。
- 例
const str = "JavaScript is awesome!"; const regex = /is/; regex.test(str); console.log(RegExp.rightContext); // " awesome!"
RegExp.prototype
編集すべての正規表現インスタンスが継承するプロトタイプオブジェクトです。
- 例
console.log(RegExp.prototype.test); // [Function: test]
RegExp.name
編集RegExp
クラスの名前を表すプロパティ(通常は "RegExp" を返します)。
- 例
console.log(RegExp.name); // "RegExp"
RegExp.length
編集RegExp
コンストラクタの引数の数を表すプロパティ(通常は 2
を返します)。
- 例
console.log(RegExp.length); // 2
インスタンスプロパティ
編集RegExp.prototype.dotAll
編集s
フラグが設定されている場合に true
を返します。
- 例
const regex = /foo.bar/s; console.log(regex.dotAll); // true
RegExp.prototype.flags
編集正規表現のフラグを文字列として返します。
- 例
const regex = /test/gi; console.log(regex.flags); // "gi"
RegExp.prototype.global
編集g
フラグが設定されている場合に true
を返します。
- 例
const regex = /test/g; console.log(regex.global); // true
RegExp.prototype.hasIndices
編集d
フラグが設定されている場合に true
を返します。
- 例
const regex = /test/d; console.log(regex.hasIndices); // true
RegExp.prototype.ignoreCase
編集i
フラグが設定されている場合に true
を返します。
- 例
const regex = /test/i; console.log(regex.ignoreCase); // true
RegExp.prototype.multiline
編集m
フラグが設定されている場合に true
を返します。
- 例
const regex = /test/m; console.log(regex.multiline); // true
RegExp.prototype.source
編集正規表現のパターン文字列を返します。
- 例
const regex = /test/g; console.log(regex.source); // "test"
RegExp.prototype.sticky
編集y
フラグが設定されている場合に true
を返します。
- 例
const regex = /test/y; console.log(regex.sticky); // true
RegExp.prototype.unicode
編集u
フラグが設定されている場合に true
を返します。
- 例
const regex = /\u{1F600}/u; console.log(regex.unicode); // true
RegExp.prototype.unicodeSets
編集v
フラグ(Unicode セット)が設定されている場合に true
を返します。
- 例
const regex = /\p{Letter}/v; console.log(regex.unicodeSets); // true
RegExp.prototype.exec()
編集文字列内で正規表現に一致する部分を検索し、詳細情報を含む配列を返します。一致しない場合は null
を返します。
- 例
const regex = /(\d+)-(\d+)/; const str = "Phone: 123-456"; const result = regex.exec(str); console.log(result); // ["123-456", "123", "456"] // result[1] は "123", result[2] は "456"
RegExp.prototype.test()
編集正規表現が文字列に一致するかをテストし、true
または false
を返します。
- 例
const regex = /hello/; console.log(regex.test("hello world")); // true console.log(regex.test("world")); // false
RegExp.prototype.toString()
編集正規表現オブジェクトを文字列として返します。
- 例
const regex = /test/gi; console.log(regex.toString()); // "/test/gi"
RegExp.prototype[@@match]()
編集文字列に正規表現を適用し、一致する部分を検索します。String.prototype.match()
によって間接的に呼び出されます。
- 例
const regex = /hello/g; const str = "hello world, hello!"; console.log(str.match(regex)); // ["hello", "hello"]
RegExp.prototype[@@replace]()
編集文字列に正規表現を適用し、一致部分を指定の文字列で置き換えます。String.prototype.replace()
によって間接的に呼び出されます。
- 例
const regex = /world/; const str = "hello world"; console.log(str.replace(regex, "universe")); // "hello universe"
RegExp.prototype[@@search]()
編集文字列に正規表現を適用し、一致する最初の位置を返します。一致しない場合は -1
を返します。String.prototype.search()
によって間接的に呼び出されます。
- 例
const regex = /world/; const str = "hello world"; console.log(str.search(regex)); // 6
RegExp.prototype[@@split]()
編集文字列を正規表現に一致する箇所で分割し、結果の配列を返します。String.prototype.split()
によって間接的に呼び出されます。
- 例
const regex = /,\s*/; const str = "apple, banana, cherry"; console.log(str.split(regex)); // ["apple", "banana", "cherry"]
PCREとRegExpオブジェクトの類似点と相違点
編集PCRE(Perl Compatible Regular Expressions)とRegExpオブジェクト(JavaScriptで使用される正規表現)は、どちらも正規表現のエンジンですが、いくつかの類似点と相違点があります。以下にその主な点を挙げます。
類似点
編集- 基本的な正規表現の構文
- 両者は基本的な正規表現の構文(リテラル文字、メタ文字、量指定子、キャプチャグループ、バックスラッシュエスケープなど)を共有しています。
- 例えば、
a*
(0回以上の'a')、(abc)
(キャプチャグループ)、a|b
(OR)などはPCREとRegExpの両方で同じ動作をします。
- フラグの使用
- 両者はフラグ(オプション)を使用して、正規表現の挙動を変更できます。例えば、
g
(グローバル)、i
(大文字小文字を区別しない)、m
(複数行モード)などがこれに該当します。
- 両者はフラグ(オプション)を使用して、正規表現の挙動を変更できます。例えば、
- リテラルの一致
- 両者は文字列に対してリテラルの一致を行う際、基本的な正規表現のパターンに基づいて一致を試みます。
相違点
編集- エンジンの違い
- PCREはPerlの正規表現エンジンを模倣したもので、Perlに近い動作をします。多くのプラットフォームで使用されており、例えばPHPやC言語でよく使用されます。
- RegExpオブジェクトは、JavaScriptの標準ライブラリに組み込まれており、主にブラウザやNode.jsで使用されます。JavaScriptの正規表現エンジンはPCREに比べてやや制限されていることが多いです。
- サポートする機能
- PCREはPerlに近い高度な機能をサポートしています。例えば、
lookahead
(先読み)やlookbehind
(後読み)、条件付き正規表現、非キャプチャグループ(?:)
、名前付きキャプチャグループ(?P<name>)
など、非常に多くの高度な機能をサポートします。 - RegExpオブジェクトは、
lookahead
やlookbehind
に関しては一部制限がありますが、最近のバージョンでは追加されつつあります。#: その他の機能(例えば、named capture groups
など)はRegExpでもサポートされており、より多くの機能がJavaScriptの進化に伴い追加されていますが、PCREに比べると機能が限定的です。
- PCREはPerlに近い高度な機能をサポートしています。例えば、
- フラグとオプション
- PCREにはいくつかの独自のフラグやオプションが存在します。例えば、
P
(Perlモード)、U
(Unicode対応)、X
(拡張モード)などが挙げられます。 - RegExpオブジェクトには、
dotAll
(ドットが改行を含む)やunicode
(Unicodeサポート)など、PCREにはないフラグもあります。
- PCREにはいくつかの独自のフラグやオプションが存在します。例えば、
- パフォーマンス
- PCREは高性能な正規表現エンジンとして知られており、大規模なデータ処理でも効率的に動作します。C言語で書かれているため、非常に速く、高度な正規表現の最適化も行われています。
- RegExpオブジェクトは、特にブラウザ環境で使われるため、多少パフォーマンスが劣る場合があります。ただし、Node.jsなどのサーバーサイドではPCREに匹敵するパフォーマンスを持つこともあります。
- Unicodeの扱い
- PCREはUnicodeに強力なサポートを提供しており、Unicode文字クラスやUnicodeの正規表現を活用することができます。
- RegExpオブジェクトは、Unicodeサポートが遅れて実装されましたが、最近では
u
フラグを使ってUnicode文字を適切に扱えるようになっています。
- エラー処理
- PCREはエラー処理が豊富で、正規表現のコンパイル時にエラーが発生すると詳細なエラーメッセージを提供します。
- RegExpオブジェクトはエラー処理がシンプルで、無効な正規表現が与えられた場合には通常、
SyntaxError
をスローします。
まとめ
編集特徴 | PCRE | RegExpオブジェクト |
---|---|---|
基盤 | Perlに基づく | JavaScript専用 |
機能 | 高度な機能(先読み、後読み、条件付きなど) | 基本的な正規表現機能(最新バージョンでは改善) |
パフォーマンス | 高速、最適化されたエンジン | やや劣るが、最近では改善されている |
Unicodeサポート | 強力なUnicodeサポート | 最近のバージョンでは改善 |
エラー処理 | 詳細なエラーメッセージ | シンプルなエラー処理 |
フラグ | 豊富なフラグ(P 、U 、X など) |
一部の独自フラグ(dotAll 、unicode など)
|
PCREは非常に強力で、特に複雑な正規表現を使用する際に役立ちます。一方で、RegExpは主にウェブ開発やJavaScript環境での利用が中心であり、使い勝手の良さや簡潔さが特徴です。どちらも用途に応じて使い分けることが重要です。
インスタンスメソッド
編集RegExp.prototype.exec(string)
編集引数で与えた文字列に正規表現を実行して、その結果を返す。 マッチする正規表現がなかった場合にはnullを返す。
const s = "abracadabra", regex = /a./g; let ary = null; while (ary = regex.exec(s)) { console.log(`${ary[0]} がマッチ、次のインデクスは ${regex.lastIndex}。`); } // ab がマッチ、次のインデクスは 2。 // ac がマッチ、次のインデクスは 5。 // ad がマッチ、次のインデクスは 7。 // ab がマッチ、次のインデクスは 9。
RegExp.prototype.test(string)
編集指定された正規表現を実行して、マッチする文字があったかどうかを真偽値型で返す。
const s = "abracadabra"; if (/ab/g.test(s)){ // ここから実際の処理 }
RegExp.prototype.toString()
編集作成した正規表現をオプション付きで返す。
console.log(new RegExp( "ab", "ig" ).toString()); // 「/ab/gi」が表示される