【JavaScript】 正規表現まとめ
更新日:2024/04/16
JavaScriptで正規表現について、必要な知識をまとめました。
正規表現の作成方法と使い方
正規表現は、RegExpオブジェクト(正規表現オブジェクト)を使用する。
RegExpオブジェクトは、正規表現のパターンを内部値として持つオブジェクトである。
RegExpオブジェクトのメソッドで正規表現のマッチングを行うが、StringオブジェクトにRegExpオブジェクトを渡すことでマッチングすることも可能。
※Stringオブジェクトの方が正規表現に関するメソッドが多い。
RegExpオブジェクトの作成方法は2種類
通常は、正規表現リテラルでRegExpオブジェクトを生成する。
不特定の正規表現パターンを使用する場合は、RegExpコンストラクターを使用する。
正規表現リテラルでの生成
正規表現リテラルは、正規表現パターンを『 / 』で囲ったものである。
例:
const rg = /(a\d)(bc)/g;
RegExpコンストラクターでの生成
正規表現パターンを動的に設定したい場合は、RegExpコンストラクターを使用する。
例:
const rg = new RegExp( "(a\\d)(bc)" , "g");
正規表現パターンを文字列リテラルで記述する場合は、的確にエスケープ文字を処理する必要がある。
重要 new RegExp()でのエスケープを参照。
正規表現のメソッド
正規表現のマッチング処理はRegExpオブジェクト自体が持っていてるメソッドを使用するケースと、Stringオブジェクトのメソッドに引数として与えるケースがある。
test()メソッド
test()はRegExpオブジェクトのメソッド。
一致するかどうかをテストし、結果としてtrueまたはfalseを返す。
例:
const testString = "abcdef";
const rg = /cde/; // 正規表現の作成
const result = rg.test( testString ); // /cde/.test( )でもOK
console.log( result ); // true
search()メソッド
search()は、Stringオブジェクトのメソッド。
最初に一致した位置(0~)を返す。
一致しない場合は、-1を返す。
例:
const testString = "abcdef";
const rg = /cde/; // 正規表現の作成
const result = testString.search( rg );
console.log( result ); // 2
match()メソッド/exec()メソッド
match()とexec()は、一致した文字列を取得するメソッド。
match()は、Stringオブジェクト(文字列オブジェクト)が持つメソッド。
一方exec()は、RegExpオブジェクト(正規表現オブジェクト)が持つメソッド。
例:
const text = "123abc#$%abc";
const rg = /abc/;
const result = rg.exec( text ); // または text.match( rg );
// 結果
// Array{
// 0 : "abc"
// 1 : "bc"
// index : 3
// input : "123abc#$%abc"
// length : 2
// }
詳しくはこちらの記事を参照。
【JavaScript】 正規表現match()とexec()の違い
こちらも参考にしてください
■【JavaScript】 matchとmatchAllの違い
replace()メソッド
replace()は、Stringオブジェクトのメソッド。
文字列の置換をおこなうメソッドだが、正規表現を使用しないと最初の一回しか置換してくれない。
全て変換したいときは、正規表現が必須となる。
例:雨を飴に置換
const text = "雨食べたい。甘い雨を食べたい。";
const rg = /雨/g;
const result = text.replace( rg , "飴" );
// 結果: 飴食べたい。甘い飴を食べたい。
詳しくはこちらの記事を参照。
【JavaScript】 replace()の使い方 単純な置換と正規表現での置換
こちらも参考にしてください
■【JavaScript】 replaceAllとは replaceとの違い
split()メソッド
replace()は、Stringオブジェクトのメソッド。
split()は、文字列を任意の文字列で分割して、配列にセットするメソッド。
任意の文字には正規表現
例:カンマまたは | で分割
const text = "abc,def|ghi";
const result = text.split( /[,|]/ );
// 結果: Array{
// 0 : "abc"
// 1 : "def"
// 2 : "ghi"
// }
詳しくはこちらの記事を参照。
【JavaScript】 split()で正規表現を使って文字列分割してみる
正規表現パターン
基本は一文字マッチの組み合わせ
正規表現はまず一文字のマッチを組み合わせる。
例:
カンマの付いた4桁の数値とマッチ
const rg = /\d,\d\d\d/;
大文字のアルファベットと3桁の数値にマッチ
const rg = /[A-Z]\d\d\d/;
次の表のパターンを使用可能。
パターン | 意味 | 例 |
---|---|---|
[ ] | [ ]内に羅列した一文字とマッチ | "abc123".match( /[b2]/g )
"b" と "2" にマッチ |
[ - ] | -で文字の範囲を指定。 [A-Z]、[a-z]、[0-9]、[A-Za-z]のように使用する [ ]内で-を検索したいときは\- | "abc123".match( /[0-9]/g )
"1" 、"2" 、"3" にマッチ "abc123".match( /[a0-9]/g )
"a"、"1"、"2"、"3" にマッチ |
[^ ] | [ ]内に羅列した文字または範囲以外とマッチ | "abc123".match( /[^ab12]/g )
"c" と "3" にマッチ "abc123".match( /[^a-z]/g )
"1"、"2" と "3" にマッチ |
. | 改行以外にマッチ | "abc".match( /.../ )
"abc" にマッチ |
\d | 数値にマッチ。 [0-9] と同じ意味。 | "abc123".match( /\d\d\d/ )
"123" にマッチ |
\D | 数値以外にマッチ。[^0-9] と同じ意味。 | "abc123".match( /\D\D\D/ )
"abc" にマッチ |
\n,\r,\r\n | 改行と一致(OSにより異なる) | "ab\r\ncd\r\nef".replace( /\r\n/g , "\n" )
改行コードを \n\r から \n に変換 |
\s | 改行・スペース・タブ・空白と一致 | /\d\s\d/.exec( "1,2 34" )
"2 3" にマッチ |
\S | \s 以外とマッチ | /\d\S\d/.exec( "1,2 34" )
"1," にマッチ |
\w | 数値・アルファベット・アンダースコア(_)にマッチ [A-Za-z0-9_]と同じ | "明日はAM8時に出発".match( /\w\w\w/ )
"AM8"にマッチ |
\W | \w以外とマッチ | "明日はAM8時に出発".match( /\W\W\W/ )
"明日は" と "時に出" にマッチ |
指定回数の繰り返し 【 {} ? 】
{ } または ? を使用すると、同じ文字(パターン)を指定した回数だけ繰り返したときマッチする。
パターン | 意味 | 例 |
---|---|---|
{ n } | 直前のパターンを n回繰り返すとマッチ | "abc123".match( /\d{3}/g )
"123" にマッチ |
{ n , m } | 直前のパターンを n回以上m回以下繰り返すとマッチ | "12_345_6789".match( /\d{3,5}/g )
"345" と "6789" にマッチ |
{ n , } | 直前のパターンを n回以上繰り返すとマッチ | "12_345_6789".match( /\d{4,}/g )
"6789" にマッチ |
? | 0回または1回繰り返すとマッチ { 0 , 1 }と同じ | "1A2_34".match( /\d[A-Z]?\d/g )
"1A2"、"34" にマッチ |
回数不明の繰り返し 【 * + 】
繰り返す回数が不明の場合、* または + を指定する。
パターン | 意味 | 例 |
---|---|---|
* | 直前のパターンを 0回以上繰り返すとマッチ | "a123_a".match( /a\d*/g )
"a123" と "a" にマッチ |
+ | 直前のパターンを 1回以上繰り返すとマッチ | "a123_a".match( /a\d+/g )
"a123" にマッチ |
結構重要:最短最長マッチ 【 ? 】
通常 * または + を使用した繰り返しは、一番長い範囲でマッチする。
例:
"12ABCD#78EF#".match( /.+#/g )
期待する結果は "12ABCD#" と "78EF#" だが、実際には "12ABCD#78EF#" がマッチする。
この場合、* または + の後に ? を使用することで最短マッチに変更できる。
(0回または1回繰り返しの?とは区別するべき)
"12ABCD#78EF#".match( /.+?#/g )
先頭・末尾マッチ 【 ^ $ 】
^ または $ は、文字列の先頭または行末にマッチする。
パターン | 意味 | 例 |
---|---|---|
^ | 先頭を意味する | "123_456".match( /^\d\d\d/ )
"123" にマッチ |
$ | 先頭を意味する | "123_456".match( /\d\d\d$/ )
"456" にマッチ |
グループ 【 ( ) 】
パターンの一部を ( ) で囲うと、囲まれた範囲はグループとなる。
グループは複数指定できる。
キャプチャグループ
グループは、マッチした文字列とは別に各々記憶(キャプチャ)される。
そのためキャプチャグループとも呼ばれる。
例:
console.log( /(ABC)DE/.exec( "ABCDEF" ) );
// 結果
// [ "ABCDE", "ABC" ]
結果配列の [0] は、マッチした文字列。
[1] は、キャプチャされた文字列。
キャプチャグループが複数ある場合は、配列の要素が増える。
exec()の結果については次のページ参照。
【JavaScript】 正規表現match()とexec()の違い
グループ単位で繰り返し
グループごとに繰り返しパターンを適用できる。
例:
console.log( /(ABC)+DE/.exec( "ABCABCDEF" ) );
// 結果
// [ "ABCABCDE", "ABC" ]
非キャプチャグループ
(?: ) のように記述されたグループは、キャプチャされない。
( ) を繰り返しで使用したいが、キャプチャさせたくないときに (?: ) を使用する。
console.log( /((?:ABC)+)DE/.exec( "ABCABCDEF" ) )
// 結果
// [ "ABCABCDE", "ABCABC" ]
通常、グループの入れ子はそれぞれキャプチャされる。
この例では内側のグループをキャプチャの対象から外している。
複数の文字列(条件)のうち一つに一致 【 | 】
| を使用すると、複数の文字列のうち一つにマッチさせることができる。
const rg = /A..|D..|G../g;
let result1;
while( (result = rg.exec( "ABC_DEF_GHI" )) !== null ){
console.log( result[0] );
}
// 結果
// ABC
// DEF
// GHI
先読み・後読みマッチ 【 (?= ) (?| ) (?<= ) (?<! ) 】
文字列の前、または後にどんな文字があるかをマッチ条件に加える。
その前後の文字はマッチした文字として取り扱わない。
パターン | 意味 | 例 |
---|---|---|
x(?=y) | 先読み。 xの後ろにyがある場合xがマッチする。 yはマッチ結果に含まれないが、 キャプチャとして取得される。 | "ABCDEFG".match(/.(?=DE)/g )
"C" にマッチ |
x(?!y) | 否定先読み。 xの後ろにyがない場合xがマッチする。 yはマッチ結果に含まれないが、 キャプチャとして取得される。 | "ABCDEFG".match(/.(?!DE)/g )
"A", "B", "D", "E", "F", "G" にマッチ |
(?<=y)x | 後読み。 xの前にyがある場合xがマッチする。 yはマッチ結果に含まれないが、 キャプチャとして取得される。 | "ABCDEFG".match(/(?<=DE)./g )
"F" にマッチ |
(?<!y)x | 否定後読み。 xの前にyがない場合xがマッチする。 yはマッチ結果に含まれないが、 キャプチャとして取得される。 | "ABCDEFG".match(/(?<!DE)./g )
"A", "B", "C", "D", "E", "G" にマッチ |
メタ文字のエスケープ 【 \ 】
メタ文字は、正規表現で特別な意味をもつ文字です。
正規表現のメタ文字:
\^.$*?|()[]{}
正規表現リテラルの場合は / を含む
通常のエスケープ
メタ文字を普通の文字としてマッチされるときは、文字の前に \ を記述します。
\\\^\.\$\*\?\|\(\)\[\]\{\}
正規表現リテラルの場合 \/
例:
/.\../g.exec( "a.bc" )
結果: "a.b"にマッチ
[ ]内のエスケープ
[ ] 内では、一部を除き普通の文字として扱われます。
そのため \ でエスケープする必要がありません。
ただし次のメタ文字はエスケープが必要です。
-]
例:
"12/ab[]cd".match( /[/ab[\]]/g )
結果:"/", "a", "b", "[", "]" にマッチ
重要 new RegExp()でのエスケープ
new RegExp()で RegExpオブジェクトを生成する場合、引数として渡す文字列中の "\" に注意が必要。
具体的には文字列リテラルから文字列を生成するときに、"\" を二つ重ねる必要がある。
不安な場合は、console.log() で文字列を出力して "\" が表示されるか確認する。
例:
const text1 = "\d";
const text2 = "\\d";
console.log( text1 ); // d 不正解
console.log( text2 ); // \d 正解
const rg = new RegExp( text2 ); // /\d/ と同等
\ をエスケープしたいときは、4つ必要。
const text3 = "\\\\d";
console.log( text3 ); // \\d
正規表現のオプションフラグ
パターン | 意味 | 例 |
---|---|---|
g | グローバルサーチ。 繰り返しマッチングをおこなう。 | "ABCDEFG".match(/[A-Z]{3}/g )
"ABC", "DEF"にマッチ |
i | 大文字小文字を区別しない | "ABCDEFG".match( /dEf/i )
"DEF" にマッチ |
s | 正規表現パラメーターの『.』が改行と一致 | "ABCD\nEFG".match(/C.*/s )
"CD↵EFG" にマッチ |
m | 行別(複数行)検索 正規表現パラメーターの『^』『$』が行ごとに適用される。 | "ABCD\nEFG".match(/..$/gm )
CD", "FG" にマッチ |
d | 照合結果に開始及び終了インデックス情報を追加する | "ABCD".match(/BC/d ).indices
indicesの内容は [ [ 1, 3 ] ] ( 配列を要素に持つ配列 ) |
u | パターン中の \u{16進数値} を、Unicodeの文字コードとして解釈する。 \p{Unicodeプロパティ名} をUnicodeプロパティとして解釈する。 コードポイント単位で処理する | "ABCDEFGa".match( /\u{42}\u{43}/u )
"BC" にマッチ "AB🐈C".match( /\p{Emoji}/u )
"🐈" にマッチ |
v | u を拡張したもの Unicodeプロパティが複数のコードポイントからなる文字も一致 [ ] で、交差( && )と差集合( -- ) を使用可能 | const text = "👩🏾⚕️";
// 複数のコードポイントであることを確認
console.log( [...text] ); // [ "👩","🏾", "", "⚕", "" ]
// uフラグでマッチング 最初のコードポイントを取得
console.log( text.match( /\p{Emoji}/u ) ); // "👩"
// vフラグでマッチング 合成を考慮して取得
console.log( text.match( /\p{RGI_Emoji}/v ) ); // "👩🏾⚕️"
※RGI_Emojiはvのみで有効 // 差集合 --
// 0-9 から 3-7 を取り除いた範囲
const rg = /[[0-9]--[3-7]]/v;
console.log(rg.test( "1" ) ); // true
console.log(rg.test( "4" ) ); // false
// 交差 &&
// あかさたな以外のひらがな
const rg = /[[\p{Script_Extensions=Hiragana}]&&[^あかさたな]]/v;
console.log(rg.test( "い" ) );// true
console.log(rg.test( "さ" ) );// false
|
y | lastIndexプロパティの位置でマッチング判定を行う。 | const rg = /\d/y;
console.log( "1A2B".match( rg ) ); // 1
rg.lastIndex = 1;
console.log( "1A2B".match( rg ) ); // null
|
更新日:2024/04/16
関連記事
スポンサーリンク
記事の内容について
こんにちはけーちゃんです。
説明するのって難しいですね。
「なんか言ってることおかしくない?」
たぶん、こんなご意見あると思います。
裏付けを取りながら記事を作成していますが、僕の勘違いだったり、そもそも情報源の内容が間違えていたりで、正確でないことが多いと思います。
そんなときは、ご意見もらえたら嬉しいです。
掲載コードについては事前に動作確認をしていますが、貼り付け後に体裁を整えるなどをした結果動作しないものになっていることがあります。
生暖かい視線でスルーするか、ご指摘ください。
ご意見、ご指摘はこちら。
https://note.affi-sapo-sv.com/info.php
このサイトは、リンクフリーです。大歓迎です。