【STEP.20】
JavaScriptの正規表現をマスターしよう!

Contents

正規表現とは

たとえば、以下の文章から郵便番号だけを取り出したいとします。

我が家の郵便番号は、184-0001です。引っ越す前は999-9763でした。

郵便番号自体はシンプルな文字列ですが、番号だけを特定するには、先頭から順番に文字を検索していき、「数値が登場したら、その次とさらに次が数値であるか、さらにその次は「-」であるか・・・・・・」を延々と判定する必要があります。

そのような煩雑な手続きを踏むことなく、あいまいな文字列パターンを検索できる仕組みが正規表現(Regular Expression)です。

たとえば郵便番号は、「0~9の数値3桁」+「-」+「0~9の数値4桁」というパターンで表せます。

これを正規表現にすると以下のようになります。

[0-9]{3}-[0-9]{4}

これをもとに文字列と比較することで、任意の文字列の中から、特定のパターンを持つ文字列を検索することができるのです。

正規表現の例

正規表現で表された文字列パターンのことを正規表現パターンといいます。

与えられた正規表現パターンが、ある文字列の中に含まれる場合、文字列が正規表現パターンにマッチするといいます。

正規表現の記法一覧

次に掲げる表に主な正規表現の記法をまとめます。

【主な正規表現パターン】
分類パターンマッチングする文字列
基本xyz「xyz」という文字列
[xyz]x、y、zのいずれか1文字
[^xyz]x、y、z以外のいずれか1文字
[a-z]a~zの間の1文字
x|y|zx、y、zのいずれか
量指定x*0文字以上のx
(”to*”は、”t”、”to”、”too”などにマッチ)
x?0、または1文字のx
(”to+”は、”t”、”to”にマッチ、”too”にマッチしない)
x+1文字以上のx
(”to+”は、”to”、”too”などにマッチ、”t”にはマッチしない)
x{n}xとn回一致
(”[0-9{4}]”は、4桁の数字)
x{n,}xとn回以上一致
(”[0-9]{4,}”は、4桁以上の数値)
x{m,n}xとm~n回一致
(”[0-9]{2,4}”は、2~4桁の数字)
位置指定^先頭に一致
$末尾に一致
文字セット.任意の1文字に一致
\w
大文字/小文字の英字、数字、アンダースコアに一致
(”[A-Za-z0-9_]”と同意)
\W
文字以外に一致
(”[
^\w
]”と同意)
\d
数字に一致
(”[0-9]”と同意)
\D
数字以外に一致
(”[^0-9]”と同意)
\n
改行(ラインフィード)に一致
\r
復帰(キャリッジリターン)に一致
\t
タブ文字に一致
\s
スペース、タブ、改ページ、改行を含む空白文字に一致
(”[
\f\n\r\t\v\u00a0\u1680\u180e\u2000-\u200a\u2028\u2029\u202f\u205f\u3000\ufeff
]”と同意)
\S
空白以外の文字に一致
(”[
^\s
]”と同意)
\p{...}
Unicode名前付きブロックに一致ES2018
\P{...}
\p{...}
の否定
(指定された文字以外に一致)ES2018
\~
~
」で表される文字
アサション
x(?=y)
xの直後にyが続く場合、xにマッチ(肯定的先読み)
x(?!y)
xの直後にyが続かない場合、xにマッチ(否定的先読み)
(?<=y)x
xの直前にyがある場合、xにマッチ(肯定的後読み)ES2018
(?<!y)x
xの直前にyがない場合、xにマッチ(否定的後読み)ES2018

RegExpオブジェクトとは

JavaScriptで正規表現パターンを解析し、検索などの機能を提供するのは、RegExpオブジェクトの役割です。

RegExpオブジェクトは、(1)RegExpコンストラクター(2)正規表現リテラル、いずれかの方法で生成します。

RegExpコンストラクター/正規表現リテラル

new RegExp(pattern, flags)  RegExpコンストラクター
/pattern/flags  正規表現リテラル
pattern    正規表現
flags      オプション

RegExpコンストラクター構文では、正規表現そのものを文字列として指定します。

また、正規表現リテラルでは、正規表現全体をスラッシュ(/)でくくる必要があります。

正規表現のオプション一覧

オプションには、次に掲げる表のような値を指定できます。

gi」のように複数指定も可能です。

【主な正規表現のオプション】
オプション概要
g文字列全体にマッチするか
i大文字/小文字の区別を無視するか
m改行コードを行頭/行末と認識するか(複数行モード)
uUnicodeで解析するかES2015
ylastIndexプロパティで指定した位置からのみマッチES2015
s「.」が改行文字(CR、LF、U+2028、U+2029)を含めたすべての文字にマッチするかES2018

正規表現の具体例

たとえば以下は、URLを検索するための正規表現パターンの例です。

let ex1 = new RegExp('http(s)?://([\\w-]+\\.)+[\\w-]+(/[\\w-./?%&=]*)?', 'gi');
	
let ex2 = /http(s)?:\/\/([\w-]+\.)+[\w-]+(\/[\w-./?%&=]*)?/gi 

最初の「http(s)?://」に含まれる「(s)?」は、「s」という文字が0または1回登場する、つまり、URL文字列が「http://」、または「https://」で始まることを表します。

次の「([\w-]+\.)+[\w-]+」は、英数字、アンダースコア、ハイフンで構成される文字列で、かつ、途中にピリオドを含むことを表しています。

そして、「(/[\w-./?%&=]*)?」は、後続の文字列が英数字、アンダースコア、ハイフン、ピリオド、スラッシュ、その他の特殊文字(?,%,&,=)を含む文字で構成されうることを表します。

正規表現におけるエスケープ処理

RegExpコンストラクター構文と正規表現リテラルでは、次のように微妙に正規表現そのものの記法が異なります。

  • RegExpコンストラクターでは「\」を「\\」でエスケープすること
  • 正規表現リテラルでは「/」を「\/」でエスケープすること

RegExpコンストラクター構文では、正規表現そのものを文字列として指定します。

JavaScriptの文字列リテラルにおいて、「\」はエスケープシーケンスを表す予約文字です。

したがって、たとえば本来の正規表現パターンである「\w」として認識させるためには、「\」を「\\」としてエスケープ処理し、「\\w」とする必要があります。

一方、正規表現リテラルにおいて、「/」は正規表現パターンの開始と終了を表す予約文字です。

正規表現リテラルで正規表現パターンそのものに「/」を含む場合には、これを「\/」のようにエスケープ処理しておく必要があります。

マッチした文字列を抽出する【match】

Stringオブジェクトのmatchメソッドを利用します。

matchメソッドの戻り値は、マッチした文字列の配列です。

matchメソッド

str.match(regexp)
regexp    正規表現

たとえば以下は、文字列に含まれるURLを列挙する例です。

let ex = /http(s)?:\/\/([\w-]+\.)+[\w-]+(\/[\w-./?%&=]*)?/gi;

let str = 'jQueryのトップページは、https://jquery.comです。';
str += 'jQueryのトップページは、HTTPS://JQUERY.COMです。';

let result = str.match(ex);
for  (let i = 0; i < result.length; i++) {
  console.log(result[i]);
}
https://jquery.com
HTTPS://JQUERY.COM

matchメソッドの挙動

ただし、正規表現パターンに指定されたオプションによって、結果が変化します。

グローバル検索(gオプション)

グローバル検索を無効にした場合、matchメソッドは最初に文字列がマッチしたところで、検索を終了します。

以下は上記のソースコードでgオプションを外した結果です。

let ex = /http(s)?:\/\/([\w-]+\.)+[\w-]+(\/[\w-./?%&=]*)?/i;

let str = 'jQueryのトップページは、https://jquery.comです。';
str += 'jQueryのトップページは、HTTPS://JQUERY.COMです。';

let result = str.match(ex);
for  (let i = 0; i < result.length; i++) {
  console.log(result[i]);
}
https://jquery.com
s
jquery.
undefined

この場合、matchメソッドは「最初に一致した文字列」と「そのサブマッチ文字列」を配列として返します。

サブマッチ文字列とは、正規表現の中で丸カッコでくくられた箇所(グループといいます。)に合致した文字列のことをいいます。

matchメソッドの挙動(gオプションを無効にした場合)

大文字/小文字の違いを無視する(iオプション)

iオプションを付与することで、大文字/小文字の違いを無視します。

以下は、先ほどのコードでiオプションを外した結果です。

大文字/小文字を区別するようになった結果、検索結果がより絞り込まれています。

let ex = /http(s)?:\/\/([\w-]+\.)+[\w-]+(\/[\w-./?%&=]*)?/g;

let str = 'jQueryのトップページは、https://jquery.comです。';
str += 'jQueryのトップページは、HTTPS://JQUERY.COMです。';

let result = str.match(ex);
for  (let i = 0; i < result.length; i++) {
  console.log(result[i]);
}
https://jquery.com

マルチラインモード【mオプション】

正規表現パターンにmオプションを付与することで、複数行モード(マルチラインモード)を有効にできます。

マルチラインモードでは、正規表現「^」(文頭)、「$」(文末)が行頭、行末にもマッチするようになります。

たとえば以下のようなサンプルで、具体的な挙動を確認してみます。

結果の上がマルチラインモードを有効にした場合、下が無効にした場合の結果です。

let ex = /^[A-Za-z]{1,}/gm;
let str = 'Helloは、こんにちは。\nByeは、さようなら。';
let result = str.match(ex);

for (let i = 0; i < result.length; i++) {
console.log(result[i]);
}
Hello
Bye
Hello

マルチラインモードを無効にした場合、「^」は文字列の先頭を表すので(=行頭にマッチしないので)、先頭の「Hello」にだけマッチします。

正規表現でUnicodeを扱う【uオプション】

正規表現パターンにuオプションを付与することで、Unicodeに関連した機能を利用できるようになります。

サロゲートペアを識別する

たとえば以下は、サロゲートペア(ここでは「
𠮟
」)を含んだ文字列を正規表現で検索する例です。
let str = '𠮟られた';
console.log(str.match(/^.られた$/gu));
// 結果:["𠮟られた"]

.」は任意の1文字を表しますが、uオプションを外すと、サロゲートペアが1文字と見なされなくなるため、結果はnullとなります。

MEMO
ーサロゲートペアー
2byteで表現できる文字数は65535文字です。

しかし、Unicodeで扱う文字が増えるにつれて、これでは不足する状況が出てきました。

そこで、一部の文字を4byteで表すことで、表現可能な文字数を拡張することとなりました。

これがサロゲートペアの意味です。

ひらがな/カタカナ/漢字などを取得する

IE×Edge×FF×

Unicodeの個々の文字には、それぞれ文字種を表すためのプロパティが割り当てられています。

これらプロパティを正規表現パターンの中で利用できるようにしたものがUnicodeプロパティエスケープという仕組みです。

\p{...}」の形式で表します。

たとえば文字列からひらがなを取り出すならば、以下のように表します。

let str = 'さくら色';
console.log(str.match(/\p{sc=Hiragana}/gu));
// 結果:["さ", "く", "ら"]

利用できるプロパティはそれこそ無数に存在しますが、よく利用するのは、次に掲げる表のようなものです。

【よく利用するUnicodeプロパティエスケープ】
プロパティ概要
\p{sc=Hiragana}
ひらがな
\p{sc=Katakana}
カタカナ
\p{sc=Han}
漢字
\p{P}
句読点

ただし、「\p{sc=Hiragana}」、「\p{sc=Katakana}」では、濁点、句読点などにマッチしません。

それらも合わせてマッチさせるには、「\p{scx=Hiragana}」、「\p{scx=Katakana}」を利用します。

また、ひらがなを含まないもの(否定)を表すには、「\P{Hiragana}」(Pが大文字)とします。

特定の位置でマッチングを試みる【yオプション】

ES2015でyオプションが追加され、lasIndexプロパティで指定された位置でマッチングを試みることができるようになりました。

let re = /JavaScript/y;
console.log(re.flags);
// 結果:y
console.log(re.test('JavaScript'));
// 結果:true
re.lastIndex = 6;
// lastIndexプロパティの位置でマッチング
console.log(re.test('Hello,JavaScript!'));
// 結果:true

console.log(re.test('Hello,JavaScript!'));」(ソースコードの8行目)では、7文字目を先頭にマッチングを試みます。

lastIndexプロパティを7、8などと変更した場合に、結果がfalse(=マッチしない)になることも確認してください。

なお、サンプルで利用しているflagsプロパティは、同じくES2015で追加となったプロパティで、現在のRegExpオブジェクトで有効になっているフラグを返します。

「.」が改行を含めたすべての文字にマッチする【sオプション】

.」は任意の1文字を表す正規表現ですが、厳密には全ての文字にマッチするわけではありません。

具体的には、CR、LFなどの改行文字に「.」はマッチしません。

これを「改行文字まで含めたすべての文字」までマッチさせるのが、sオプションの役割です。

let re = /Hello.JavaScript!/s;
let str = 'Hello\nJavaScript!';
console.log(re.test(str));
// 結果:true

.」が改行(\n)にマッチした結果、testメソッドはtrueを返します。

sオプションを削除した場合、結果がfalse(=マッチしない)となることも確認してください。

文字列がマッチするかどうかだけを確認する【test/search】

testメソッドを利用する方法

正規表現パターンの文字列がマッチするかどうかだけを確認したいならば(マッチした文字列の抽出が不要ならば)、testメソッドを利用します。

testメソッド

regexp.test(str)
str    検索対象文字列

たとえば以下は文字列にURLが含まれるかを確認する例です。

let ex1 = /http(s)?:\/\/([\w-]+\.)+[\w-]+(\/[\w-./?%&=]*)?/gi;
		
let str1 = 'jQueryはhttps://jquery.comからダウンロードできます。';
let str2 = 'JavaScriptはスクリプト言語です。';
	
console.log(ex1.test(str1));
// 結果:true
console.log(ex1.test(str2));
// 結果:false

searchメソッドを利用する方法

あるいは、Stringオブジェクトのsearchメソッドを利用することも可能です。

searchメソッド

str.search(regexp)
regexp    正規表現

searchメソッドはマッチした文字列が見つかった文字位置を返します(先頭文字は0)。

文字列が見つからなかった場合は、searchメソッドは「-1」を返します。

let ex1 = /http(s)?:\/\/([\w-]+\.)+[\w-]+(\/[\w-./?%&=]*)?/gi;
		
let str1 = 'jQueryはhttps://jquery.comからダウンロードできます。';
let str2 = 'JavaScriptはスクリプト言語です。';
	
console.log(str1.search(ex1));
// 結果:7
console.log(str2.search(ex1));
// 結果:-1

できるだけ短い文字列にマッチさせる【最短一致】

正規表現の既定の動作は最長一致です。

最長一致とは、正規表現で「*」「+」などの量指定子を利用した場合、できるだけ長い文字列に一致させなさい、というルールです。

まずは、その具体的な挙動を確認します。

let tags = '<p><a href="https://jquery.com/"><strong>jQueryのトップページ</strong></a></p>';

let ex = /<.+>/g;

let result = tags.match(ex);

for (let i = 0; i < result.length; i++) {
  console.log(result[i]);
}

<.+>」は、「<...>の中に1つ以上の文字」を表し、「<p>」、「<a href="...">」、「<strong>」のようなタグにマッチすることを想定しています。

この例であれば、それぞれタグを分解して、以下のような結果を期待しています。

<p>
<a href="https://jquery.com/">
<strong>
</strong>
</a>
</p>

しかし、実際の結果はすべてのタグ文字列がまとめてマッチされてしまい、結果は以下のようになります。

<p><a href="https://jquery.com/"><strong>jQueryのトップページ</strong></a></p>

これが「できるだけ長い文字列に一致」させる、最長一致の意味です。

もし意図したように個々のタグにマッチさせたいならば、「let ex = /<.+>/g;」を以下のように書き換えます。

let ex = /<.+?>/g;

+?」は最短一致(できるだけ短い文字列に一致)を意味するので、今度は期待した結果が得られます。

同様に「*?」「??」「{2,5}?」のような表現も可能です。

正規表現での検索結果をより詳細に取得する【exec】

RegExpオブジェクトのexecメソッドを利用します。

execメソッド

regexp.exec(str)
str    文字列

たとえば以下は、文字列に含まれるURLをすべて抽出する例です。

let ex = /http(s)?:\/\/([\w-]+\.)+[\w-]+(\/[\w-./?%&=]*)?/gi;

let str = 'jQueryのトップページは、https://jquery.comです。';
str += 'jQueryのトップページは、HTTPS://JQUERY.COMです。';
		
let result;

while ((result = ex.exec(str)) != null) {
  console.log(result[0]);   
}
https://jquery.com
HTTPS://JQUERY.COM

execメソッドは、matchメソッドにも似ていますが、以下のような特徴を持っています。

戻り値は常に1つのマッチング結果

グローバル検索の有効/無効に関わらず、一度に1つのマッチング結果しか返しません。

代わりに、「マッチング文字列全体」と「そのサブマッチ文字列」を返します。

この例であれば、マッチングした文字列全体を取得したいので、決め打ちで「result[0]」にアクセスしています。(サブマッチ文字列を取得するならば、「result[1]」以降にアクセスします。)

execメソッドの戻り値は配列を拡張したもので、次に掲げる表のようなプロパティが含まれています。

【execメソッドの戻り値(プロパティ)】
プロパティ概要
index見つかった文字位置
input入力文字列
groups名前付きキャプチャグループにマッチした文字列

検索位置を記憶する

RegExpオブジェクトでは、最後にマッチした文字位置を記憶しており、次回の呼び出しではその位置から検索を開始します。

サンプルでは、この性質を利用して、execメソッドがnullを返す(=マッチする文字列がなくなる。)までループを繰り返すことで、すべてのマッチング結果を得ています。

次回の検索位置は、RegExpオブジェクトのlastIndexプロパティから取得できます。

ただし、グローバル検索(gオプション)が無効の場合、lastIndexプロパティは「0」のまま変化しません。

execメソッドの挙動

正規表現パターンのグループに名前を付ける【名前付きグループキャプチャ】

IE×Edge×FF×

(...)」でくくられたグループには「?<名前>」の形式で名前を付与することも可能です。(名前付きグループキャプチャ

たとえば以下は、メールアドレスを表す正規表現で、ローカル部を「?<localName>」、ドメイン部を「?<domain>」、とそれぞれ命名した例です。

let ex = /(?<localName>[a-z0-9.!#$%&'*+/=?^_{|}~-]+)@(?<domain>[a-z0-9-]+(?:\.[a-z0-9-]+)*)?/i;

let mail = 'メールアドレスは、biohazardlevelmouth@yahoo.co.jpです。';

let result = mail.match(ex);

console.log(`メールアドレスは、${result.groups.domain}の${result.groups.localName}です。`);

// 結果:メールアドレスは、yahoo.co.jpのbiohazardlevelmouthです。

名前付けされた部分にアクセスするにはmatchexec)メソッドの戻り値からgroupsプロパティを参照します。

前方で宣言した名前を参照する(後方参照)

正規表現パターンの中で宣言した名前を、「\k<名前>」の形式で、あとから参照することも可能です。

これによって、1つのパターンの中で同じサブパターンが登場する場合にも、より簡潔に表現できます。

たとえば以下は文字列から「<a href="...">...</a>」(「...」は同じ文字列)を取り出す例です。

let site = '<p><a href="https://jquery.com/">https://jquery.com/</a></p>';

let ex = /<a href="(?<link>.+?)">\k<link><\/a>/;

console.log(site.match(ex)[0]);

// 結果:<a href="https://jquery.com/">https://jquery.com/</a>

正規表現で文字列を置換する

Stringオブジェクトのreplaceメソッドを利用します。

replaceメソッド

str.replace(regexp, substr)
regexp    正規表現
substr    置換後の文字列

たとえば以下は、文中に含まれる電話番号「999-9999-9999」を「999(9999)9999」の形式に変換する例です。

let ex = /(0\d{1,4})-(\d{1,4})-(\d{3,4})/gi;

let str = 'お問い合わせは、000-0000-0000まで。休日は、0111-11-1111まで。';

let result = str.replace(ex, '$1($2)$3');
		
console.log(result);
お問い合わせは、000(0000)0000まで。休日は、0111(11)1111まで。

引数substrには、次に掲げる表のような特殊変数を埋め込むことができます。

サンプルでは$1$3を利用することで、市外局番($1)、市内局番($2)、加入者番号($3)を、それぞれ置き換え後の文字列に埋め込んでいます。

【replaceメソッドで利用できる特殊変数
(元の文字列が「電話番号は、000-000-0000です。」の場合)】
変数概要戻り値(例)
$&マッチした部分文字列000-000-0000
$`マッチした部分文字列の直前の文字列電話番号は、
$'マッチした部分文字列の直後の文字列です。
$1~100サブマッチ文字列000($1の場合)

名前付きキャプチャグループと後方参照を利用した例

ES2018IE×Edge×FF×

名前付きキャプチャグループと後方参照を利用すれば以下のようなコードを記述することも可能です。

replaceメソッドで後方参照するには、「$<名前>」のようにします。

let ex = /(?<area>0\d{1,4})-(?<city>\d{1,4})-(?<sub>\d{3,4})/gi;

let str = 'お問い合わせは、000-0000-0000まで。休日は、0111-11-1111まで。';

let result = str.replace(ex, '$<area>($<city>)$<sub>');
		
console.log(result);
お問い合わせは、000(0000)0000まで。休日は、0111(11)1111まで。

URL文字列をアンカータグに変換例

以下は、予約変数「$&」を使って、文中のURLをアンカータグに変換する例です。

let ex = /http(s)?:\/\/([\w-]+\.)+[\w-]+(\/[\w-./?%&=]*)?/gi;

let str = 'jQueryのトップページは、https://jquery.comです。';

console.log(str.replace(ex, '<a href="$&">$&</a>'));
jQueryのトップページは、<a href="https://jquery.com">https://jquery.com</a>です。
MEMO
ーgオプションに注意ー
グローバル検索(gオプション)を有効にしていない場合、マッチする文字列が複数あっても、最初の1つしか置き換えされません。

固定文字列で置き換える例

replaceメソッドの第1引数には、正規表現だけではなく文字列リテラルを指定することもできます。

その場合は、単に、固定文字列での置き換えが行われます。

let sub = 'もも';
let str = 'ももから生まれたももたろう';

console.log(str.replace(sub,'桃'));
// 結果:桃から生まれたももたろう

ただし、固定文字列での置き換えでは、最初の1つしか置き換えされません。

複数の置き換えには、以下のようなテクニックを利用します。

let str = 'ももから生まれたももたろう';

console.log(str.split('もも').join('桃'));
// 結果:桃から生まれた桃たろう

置き換え前の文字列(ここでは「もも」)で文字列を分割し、置き換え後の文字列(ここでは「」)で再度連結しています。

コールバック関数で複雑な置き換えも可能

replaceメソッドの第2引数には、関数(function型)を渡すこともできます。

たとえば以下は、文中のURLをすべて小文字に変換する例です。

let ex = /http(s)?:\/\/([\w-]+\.)+[\w-]+(\/[\w-./?%&=]*)?/gi;

let str = 'jQueryのトップページは、HTTPS://JQUERY.COMです。';
	
let result = str.replace(ex, function (match, p1, p2, p3, offset, string) {
  return match.toLowerCase();
});
		
console.log(result);
jQueryのトップページは、https://jquery.comです。

コールバック関数は、次に掲げる表のような引数を受け取り、戻り値として置き換え後の文字列返します。

この例であれば、引数match(マッチした文字列)を小文字に変換したものを戻り値として返しています。

【コールバック関数の引数】
引数概要
matchマッチした文字列
p1,p2,p3...サブマッチ文字列(可変長引数)
offsetマッチした文字列位置
stringマッチング対象の文字列

正規表現で文字列を分割する【split】

Stringオブジェクトのsplitメソッドを利用します。

splitメソッド

str.split([separator [,limit]])
separator  区切り文字
limit      分割の最大数

まずは、具体的な例を見てみましょう。

console.log('Java Script\nスクリプト言語'.split(/[\s\n]/));
console.log('Java Scriptはスクリプト言語'.split('は'));
console.log('Java Script'.split(''));
console.log('Java Script'.split());
console.log('Java Script\nスクリプト言語'.split(/[\s\n]/, 2));
["Java", "Script", "スクリプト言語"]
["Java Script", "スクリプト言語"]
["J", "a", "v", "a", " ", "S", "c", "r", "i", "p", "t"]
["Java Script"]
["Java", "Script"]

引数separatorには、正規表現(.split(/[\s\n]/))、文字列(.split('は'))、いずれを利用しても構いません。

replaceメソッドと異なり、gオプションの有無に関わらず、splitメソッドは文字列全体を分割の対象とします。

引数separatorが空文字列の場合(.split(''))、splitメソッドは文字列を文字配列に変換します。

ただし、引数separatorを省略した場合(.split())には戻り値は元の文字列を1つに含んだ配列となります。

紛らわしい点なので、注意が必要です。

.split(/[\s\n]/,2)は、引数limitを指定した場合です。

この場合、splitメソッドは引数limitを上限に文字列を分割します。

上限を超えた部分の文字列は切り捨てられます。

区切り文字を結果に含める例

splitメソッドは、既定で結果に区切り文字を含めません。

区切り文字を結果にも反映させたい場合には、引数separatorに「(...)」でグループを含めるようにします。

(...)」にマッチした文字列は、結果配列にも反映されます。

たとえば以下は数値で文字列を分割する例です。

区切り文字となった数値も含まれる点に注目です。

let str = '桃栗3年柿8年';
console.log(str.split(/(\d)/));
// 結果:["桃栗", "3", "年柿", "8", "年"]

肯定的先読みと否定的後読み

正規表現では、前後の文字列の有無によって、本来の文字列がマッチするかを判定する表現があります。

【後読みと先読み】
表現概要
A(?=B)肯定的先読み(Aの直後にBが続く場合にだけ、Aにマッチ)
A(?!B)否定的先読み(Aの直後にBが続かない場合だけ、Aにマッチ)
(?<=B)A肯定的後読み(Aの直前にBがある場合だけ、Aにマッチ)
(?<!B)A否定的後読み(Aの直前にBがない場合だけ、Aにマッチ)

このうち、先読みは以前からあったものですが、長らく後読みには未対応でした。

これがES2018でようやくサポートされました。

let re1 = /いろ(?=はに)/g;
let re2 = /いろ(?!はに)/g;
let re3 = /(?<=。)いろ/g;
let re4 = /(?<!。)いろ/g;
let msg1 = 'いろはにほへと';
let msg2 = 'いろものですね。いろいろと';
console.log(msg1.match(re1));  
// 結果:[いろ]
console.log(msg2.match(re1));  
// 結果:null
console.log(msg1.match(re2));  
// 結果:null
console.log(msg2.match(re2));  
// 結果:[いろ,いろ,いろ]
console.log(msg1.match(re3));  
// 結果:null
console.log(msg2.match(re3));  
// 結果:[いろ]
console.log(msg1.match(re4));  
// 結果:[いろ]
console.log(msg2.match(re4));  
// 結果:「いろ,いろ」

先読み、後読みに関わらず、カッコの中はマッチング結果には含まれない点に注意が必要です。


コメントを残す

メールアドレスが公開されることはありません。 * が付いている欄は必須項目です