JavaScriptの正規表現の簡単なガイド

JavaScriptの学習に興味がありますか? jshandbook.comで無料の電子ブックを入手

正規表現の紹介

正規表現(略してregexとも呼ばれます)は、テキスト文字列を処理する高速な方法です。

特別な構文で正規表現を定式化することにより、次のことができます。

  • 文字列内のテキストを検索する
  • 文字列の部分文字列を置き換えます
  • 文字列から情報を抽出します

ほとんどすべてのプログラミング言語は、正規表現の実装を特徴としています。各実装にはわずかな違いがありますが、一般的な概念はほぼすべての場所に適用されます。

正規表現は、文字列処理アルゴリズムの概念的な検索パターンとして形式化された1950年代にさかのぼります。

grep、sedなどのUNIXツール、および一般的なテキストエディタに実装された正規表現は、人気が高まりました。これらはPerlプログラミング言語に導入され、後に他の多くの言語にも導入されました。

JavaScriptは、Perlとともに、言語に直接組み込まれた正規表現をサポートするプログラミング言語の1つです。

ハードだが便利

正規表現は、初心者には絶対的なナンセンスのように見えますが、プロの開発者にとっても、それらを理解するのに必要な時間をかけなければ、何度も同じように思えます。

不可解な正規表現は、書くのが難しく、読むのが難しく、保守/修正するのが難しいです。

ただし、正規表現が文字列操作を実行する唯一の正しい方法である場合もあるため、ポケットの中の非常に価値のあるツールです。

このチュートリアルは、JavaScriptの正規表現を簡単な方法で紹介し、正規表現を読んで作成するためのすべての情報を提供することを目的としています。

経験則として、単純な正規表現は読み書きが簡単ですが、複雑な正規表現は、基本を深く理解していなければすぐに混乱する可能性があります。

正規表現はどのように見えますか?

JavaScriptでは、正規表現はオブジェクトであり、2つの方法で定義できます。

1つ目は、コンストラクターを使用して新しいRegExpオブジェクトをインスタンス化することです。

const re1 = new RegExp( 'hey')

2番目は、正規表現リテラル形式を使用しています。

const re1 = / hey /

JavaScriptにはオブジェクトリテラルと配列リテラルがあることを知っていますか?また、正規表現リテラルもあります。

上記の例では、ちょっとはパターンと呼ばれます。リテラル形式ではスラッシュで区切られますが、オブジェクトコンストラクターではスラッシュで区切られません。

これは2つの形式の最初の重要な違いですが、他の形式については後で説明します。

どのように機能しますか?

上記のre1として定義した正規表現は非常に単純なものです。文字列heyを制限なしで検索します。文字列には多くのテキストを含めることができますが、途中で正規表現が満たされます。また、ちょっとだけを含めることもでき、正規表現も同様に満足されます。

とても簡単です。

ブール値を返すRegExp.test(String)を使用して正規表現をテストできます。

re1.test( 'hey')//
re1.test( 'blablabla hey blablabla')//
re1.test( 'he')//
re1.test( 'blablabla')//

上記の例では、「hey」がre1に格納されている正規表現パターンを満たしているかどうかを確認しました。

これは最も簡単な方法ですが、正規表現に関する多くの概念をすでに知っています。

固定

/ hey /

ストリング内のどこにでも一致します。

heyで始まる文字列に一致させる場合は、^演算子を使用します。

/^hey/.test('hey ')//
/^hey/.test('bla hey ')//

heyで終わる文字列に一致させる場合は、$演算子を使用します。

/hey$/.test('hey ')//
/hey$/.test('bla hey ')//
/hey$/.test('hey you ')//

それらを組み合わせて、ちょっと、ちょうどその文字列に完全に一致する文字列に一致します:

/^hey$/.test('hey ')//

部分文字列で始まり、別の文字列で終わる文字列を一致させるには、0回以上繰り返される任意の文字に一致する。*を使用できます。

/^hey.*joe$/.test('hey joe ')//
/^hey.*joe$/.test('heyjoe ')//
/^hey.*joe$/.test('hey how are you joe ')//
/^hey.*joe$/.test('hey joe! ')//

範囲内のアイテムを一致させる

特定の文字列を照合する代わりに、次のように範囲内の任意の文字と照合することを選択できます。

/ [a-z] / //a、b、c、...、x、y、z
/ [A-Z] / //A、B、C、...、X、Y、Z
/ [a-c] / // a、b、c
/ [0-9] / //0、1、2、3、...、8、9

これらの正規表現は、これらの範囲の文字を少なくとも1つ含む文字列に一致します。

/[a-z]/.test('a ')//
/[a-z]/.test('1 ')//
/[a-z]/.test('A ')//
/[a-c]/.test('d ')//
/[a-c]/.test('dc ')//

範囲は組み合わせることができます:

/ [A-Za-z0-9] /
/[A-Za-z0-9]/.test('a ')//
/[A-Za-z0-9]/.test('1 ')//
/[A-Za-z0-9]/.test('A ')//

範囲アイテムを複数回一致させる

-charを使用すると、文字列に範囲内の1文字のみが含まれているかどうかを確認できます。

/ ^ [A-Za-z0-9] $ /
/^[A-Za-z0-9]$/.test('A ')//
/^[A-Za-z0-9]$/.test('Ab ')//

パターンを否定する

パターンの先頭にある^文字は、文字列の先頭に固定します。

範囲内で使用すると、無効になります。

/[^A-Za-z0-9]/.test('a ')//
/[^A-Za-z0-9]/.test('1 ')//
/[^A-Za-z0-9]/.test('A ')//
/[^A-Za-z0-9]/.test('@ ')//
  • \ dは、[0-9]と同等の任意の数字に一致します
  • \ Dは、数字ではない任意の文字と一致します。[^ 0-9]と同等です
  • \ wは[A-Za-z0-9]と同等の任意の英数字と一致します
  • \ Wは、[^ A-Za-z0-9]と同等の任意の非英数字に一致します
  • \ sは空白文字に一致します:スペース、タブ、改行、Unicodeスペース
  • \ Sは、空白ではない任意の文字に一致します
  • \ 0はnullと一致します
  • \ nは改行文字に一致します
  • \ tはタブ文字に一致します
  • \ uXXXXは、コードXXXXのUnicode文字に一致します(uフラグが必要です)
  • 。改行文字以外の任意の文字(たとえば、\ n)に一致します(後で説明するsフラグを使用しない限り)
  • [^]は、改行文字を含む任意の文字に一致します。複数行の文字列で役立ちます。

正規表現の選択肢

ある文字列または別の文字列を検索する場合は、|を使用しますオペレーター。

/hey|ho/.test('hey ')//
/hey|ho/.test('ho ')//

量指定子

文字列に1桁の数字が含まれているかどうかをチェックするこの正規表現があるとします。

/ ^ \ d $ /

使用できますか?オプションにするための量指定子。したがって、ゼロまたは1つが必要です。

/ ^ \ d?$ /

しかし、複数の数字を一致させたい場合はどうでしょうか?

+、*、{n}および{n、m}を使用して、4つの方法でそれを行うことができます。これらを一つ一つ見ていきましょう。

+

1つ以上(> = 1)のアイテムに一致

/ ^ \ d + $ /
/^\d+$/.test('12 ')//
/^\d+$/.test('14 ')//
/^\d+$/.test('144343 ')//
/ ^ \ d + $ /。test( '')//
/^\d+$/.test('1a ')//

*

0個以上(> = 0)のアイテムに一致

/ ^ \ d + $ /
/^\d*$/.test('12 ')//
/^\d*$/.test('14 ')//
/^\d*$/.test('144343 ')//
/ ^ \ d * $ /。test( '')//
/^\d*$/.test('1a ')//

{n}

正確にn個のアイテムに一致

/ ^ \ d {3} $ /
/^\d{3}$/.test('123 ')//
/^\d{3}$/.test('12 ')//
/^\d{3}$/.test('1234 ')//
/^[A-Za-z0-9]{3}$/.test('Abc ')//

{n、m}

n回とm回の一致:

/ ^ \ d {3,5} $ /
/^\d{3,5}$/.test('123 ')//
/^\d{3,5}$/.test('1234 ')//
/^\d{3,5}$/.test('12345 ')//
/^\d{3,5}$/.test('123456 ')//

mは省略可能なため、少なくともn個のアイテムがあります。

/ ^ \ d {3、} $ /
/^\d{3,}$/.test('12 ')//
/^\d{3,}$/.test('123 ')//
/^\d{3,}$/.test('12345 ')//
/^\d{3,}$/.test('123456789 ')//

オプション品

アイテムの後に?オプションにします:

/ ^ \ d {3} \ w?$ /
/^\d{3}\w?$/.test('123 ')//
/^\d{3}\w?$/.test('123a ')//
/^\d{3}\w?$/.test('123ab ')//

グループ

括弧を使用して、文字のグループを作成できます:(...)

この例では、正確に3桁の数字とそれに続く1つ以上の英数字が一致します。

/ ^(\ d {3})(\ w +)$ /
/^(\d{3})(\w+)$/.test('123 ')//
/^(\d{3})(\w+)$/.test('123s ')//
/^(\d{3})(\w+)$/.test('123something ')//
/^(\d{3})(\w+)$/.test('1234 ')//

グループを閉じる括弧の後に置かれた繰り返し文字は、グループ全体を指します。

/ ^(\ d {2})+ $ /
/^(\d{2})+$/.test('12 ')//
/^(\d{2})+$/.test('123 ')//
/^(\d{2})+$/.test('1234 ')//

キャプチャグループ

これまで、文字列をテストし、特定のパターンが含まれているかどうかを確認する方法を見てきました。

正規表現の非常に優れた機能は、文字列の一部をキャプチャし、配列に入れる機能です。

これは、グループ、特にグループのキャプチャを使用して実行できます。

デフォルトでは、グループはキャプチャグループです。ここで、パターンが満たされた場合にブール値を返すRegExp.test(String)を使用する代わりに、String.match(RegExp)またはRegExp.exec(String)を使用します。

これらはまったく同じであり、最初のアイテムに一致した文字列全体を含む配列を返し、次に一致した各グループのコンテンツを返します。

一致するものがない場合、nullを返します。

'123s'.match(/ ^(\ d {3})(\ w +)$ /)
//配列["123s"、 "123"、 "s"]
/^(\d{3})(\w+)$/.exec('123s ')
//配列["123s"、 "123"、 "s"]
'hey'.match(/(hey | ho)/)
// Array ["hey"、 "hey"]
/(hey|ho)/.exec('hey ')
// Array ["hey"、 "hey"]
/(hey|ho)/.exec('ha! ')
//ヌル

グループが複数回一致する場合、最後の一致のみが結果配列に配置されます。

'123456789'.match(/(\ d)+ /)
//配列["123456789"、 "9"]

オプションのグループ

キャプチャグループは、(...)?を使用してオプションにすることができます。見つからない場合、結果の配列スロットには未定義が含まれます。

/^(\d{3})(\s)?(\w+)$/.exec('123 s ')
//配列["123 s"、 "123"、 ""、 "s"]
/^(\d{3})(\s)?(\w+)$/.exec('123s ')
// Array ["123s"、 "123"、undefined、 "s"]

参照一致グループ

一致するすべてのグループには番号が割り当てられます。 $ 1は最初のものを指し、$ 2は2番目のものを指します。これは、後で文字列の一部を置き換えることについて話すときに役立ちます。

名前付きキャプチャグループ

これは新しいES2018機能です。

結果の配列のスロットを単に割り当てるのではなく、グループを名前に割り当てることができます。

const re = /(?<年> \ d {4})-(?<月> \ d {2})-(?<日> \ d {2})/
const result = re.exec( '2015-01-02')
// result.groups.year === '2015';
// result.groups.month === '01';
// result.groups.day === '02';

グループなしでmatchおよびexecを使用する

グループなしでmatchとexecを使用することには違いがあります。配列の最初の項目は、一致した文字列全体ではなく、直接一致します

/hey|ho/.exec('hey ')
// ["hey"]
/(hey).(ho)/.exec('hey ho ')
// ["hey ho"、 "hey"、 "ho"]

非キャプチャグループ

デフォルトのグループはキャプチャグループであるため、結果の配列内のいくつかのグループを無視する方法が必要です。これは、(?:...)で始まる非キャプチャグループを使用して可能です。

'123s'.match(/ ^(\ d {3})(?:\ s)(\ w +)$ /)
//ヌル
'123 s'.match(/ ^(\ d {3})(?:\ s)(\ w +)$ /)
//配列["123 s"、 "123"、 "s"]

任意の正規表現で次のフラグを使用できます。

  • g:パターンに複数回一致します
  • i:正規表現の大文字と小文字を区別しません
  • m:マルチラインモードを有効にします。このモードでは、^と$は文字列全体の開始と終了に一致します。これがない場合、複数行の文字列では、各行の先頭と末尾に一致します。
  • u:Unicodeのサポートを有効にします(ES6 / ES2015で導入)
  • s:(ES2018の新機能)単一行の短縮形。改行文字にも一致します。

フラグは組み合わせることができ、正規表現リテラルの文字列の最後に追加されます。

/hey/ig.test('HEy ')//

または、RegExpオブジェクトコンストラクターの2番目のパラメーターとして:

new RegExp( 'hey'、 'ig')。test( 'HEy')//

正規表現の検査

正規表現を指定すると、そのプロパティを検査できます。

  • パターン文字列のソース
  • mフラグのある複数行true
  • gフラグを使用したグローバルtrue
  • ignoreCaseはiフラグでtrue
  • lastIndex
/^(\w{3})$/i.source // "^(\\ d {3})(\\ w +)$"
/^(\w{3})$/i.multiline // false
/^(\w{3})$/i.lastIndex // 0
/^(\w{3})$/i.ignoreCase // true
/^(\w{3})$/i.global // false

逃げる

これらの文字は特別です:

  • \
  • /
  • []
  • ()
  • {}
  • +
  • *
  • |
  • ^
  • $

これらは、正規表現パターンで意味を持つ制御文字であるため、特別です。パターン内で一致する文字として使用したい場合は、バックスラッシュを前に付けてエスケープする必要があります。

/ ^ \\ $ /
/ ^ \ ^ $ / // /^\^$/.test('^ ')
/ ^ \ $$ / // /^\$$/.test('$ ')

ストリング境界

\ bおよび\ Bを使用すると、文字列が単語の先頭または末尾にあるかどうかを検査できます。

  • \ bは、単語の先頭または末尾の文字セットに一致します
  • \ Bは、単語の先頭または末尾にない文字セットに一致します

例:

'私は熊を見た' .match(/ \ bbear /)//配列["熊"]
「あごひげを見た」match(/ \ bbear /)// Array ["bear"]
「あごひげを見た」match(/ \ bbear \ b /)// null
'cool_bear'.match(/ \ bbear \ b /)// null

置換、正規表現を使用

文字列にパターンが含まれているかどうかを確認する方法はすでに見ました。

また、パターンに一致する文字列の一部を配列に抽出する方法も説明しました。

パターンに基づいて文字列の一部を置き換える方法を見てみましょう。

JavaScriptのStringオブジェクトにはreplace()メソッドがあります。このメソッドは、正規表現なしで使用して、文字列で単一の置換を実行できます。

「Hello world!」。replace( 'world'、 'dog')
//ハロードッグ!
「私の犬は良い犬です!」replace( 'dog'、 'cat')
//私の猫は良い犬です!

このメソッドは、引数として正規表現も受け入れます。

「Hello world!」。replace(/ world /、 'dog')// Hello dog!

gフラグの使用は、バニラJavaScriptの文字列内の複数の出現を置換する唯一の方法です。

「私の犬は良い犬です!」。replace(/ dog / g、 'cat')
//私の猫は良い猫です!

グループを使用すると、文字列の一部を移動するなど、より洗練されたことができます。

「こんにちは、世界!」replace(/(\ w +)、(\ w +)!/、 '$ 2:$ 1 !!!')
// "world:Hello !!!"

文字列を使用する代わりに、関数を使用して、より洗練された処理を行うこともできます。 String.match(RegExp)またはRegExp.exec(String)によって返されるような多くの引数を受け取ります。引数の数はグループの数に依存します。

「Hello、world!」。replace(/(\ w +)、(\ w +)!/、(matchedString、first、second)=> {
  console.log(first);
  console.log(second);
  `$ {second.toUpperCase()}を返します:$ {first} !!!`
})
//「WORLD:Hello !!!」

貪欲

正規表現はデフォルトで貪欲であると言われています。

どういう意味ですか?

この正規表現を取ります:

/\$(.+)\s?/

文字列からドルの量を抽出することになっています。

/ \ $(。+)\ s?/。exec( 'これは100ドルかかります')[1]
// 100

しかし、数字の後にもっと言葉があると、おかしくなります。

/ \ $(。+)\ s?/。exec( 'これは100ドルで200ドル未満です')[1] // 100および200ドル未満です

どうして? $記号の後の正規表現は、。+の任意の文字と一致し、文字列の最後に到達するまで停止しないためです。それから、\ s?終了スペースをオプションにします。

これを修正するには、正規表現に遅延を指定し、可能な限り最小限のマッチングを実行する必要があります。 ?を使用してこれを行うことができます。量指定子の後の記号:

/ \ $(。+?)\ s / .exec( 'これは100ドルで200ドル未満です)[1]
// 100
?を削除しました\ sの後。それ以外の場合、スペースはオプションだったため、最初の数字のみに一致しました

そう、 ?数量詞とレイジーモードインジケーターの両方になりうるため、その位置に基づいて異なることを意味します。

先読み:後に続くものに応じて文字列を一致させます

?=を使用して、特定のサブストリングが後に続くストリングと一致します。

/ロジャー(?=ウォーターズ)/
/ Roger(?= Waters)/。test( 'Roger is my dog')// false
/ Roger(?= Waters)/。test(「ロジャーは私の犬であり、ロジャー・ウォーターズは有名なミュージシャンです」)
// true

?!文字列の後に特定の部分文字列が続かない場合に一致する逆の操作を実行します。

/ロジャー(?!ウォーターズ)/
/ Roger(?! Waters)/。test( 'Roger is my dog')// true
/ Roger(?! Waters)/。test( 'Roger Watersは有名なミュージシャンです)
// false

後読み:前にあるものに応じて文字列を一致させる

これはES2018の機能です。

先読みでは?=記号を使用します。後読みは?<=を使用します。

/(?<= Roger)Waters /
/(?<= Roger)Waters / .test( 'Pink Waters is my dog')
// false
/(?<= Roger)Waters / .test(「ロジャーは私の犬で、ロジャー・ウォーターズは有名なミュージシャンです」)
// true

後読みは?<!を使用して無効になります。

/(?<!Roger)Waters /
/(?<!Roger)Waters / .test( 'Pink Waters is my dog')
// true
/(?<!Roger)Waters / .test(「ロジャーは私の犬であり、ロジャー・ウォーターズは有名なミュージシャンです」)
// false

正規表現とユニコード

Unicode文字列を使用する場合、uフラグは必須です。特に、これはアストラルプレーン(最初の1600個のUnicode文字に含まれていないプレーン)の文字を処理する必要がある場合に適用されます。

絵文字は良い例ですが、それだけではありません。

このフラグを追加しないと、1文字に一致するこの単純な正規表現は機能しません。JavaScriptの場合、絵文字は内部的に2文字で表されるためです(JavaScriptのUnicodeを参照)。

/^.$/.test('a ')//
/^.$/.test(' ')//
/^.$/u.test(' ')//

したがって、常にuフラグを使用してください。

Unicodeは、通常の文字と同様に、範囲を処理します。

/[a-z]/.test('a ')//
/[1-9]/.test('1 ')//
/[-]/u.test(' ')//
/[-]/u.test(' ')//

JavaScriptは内部コード表現をチェックするため、\ u1F436 <\ u1F43A <\ u1F98Aであるため、<<となります。絵文字の完全なリストを確認して、これらのコードを取得し、順序を確認してください(ヒント:macOS絵文字ピッカーにはいくつかの絵文字が混在した順序であるため、頼りにしないでください)。

Unicodeプロパティエスケープ

上記で見たように、正規表現パターンでは、\ dを使用して任意の数字を一致させ、\ sを使用して空白以外の文字を一致させ、\ wを使用して任意の英数字を一致させることができます。

Unicodeプロパティエスケープは、非常にクールな機能を導入するES2018機能であり、この概念を\ p {}およびその否定\ P {}を導入するすべてのUnicode文字に拡張します。

Unicode文字には、プロパティのセットがあります。たとえば、スクリプトは言語ファミリを決定し、ASCIIはASCII文字に当てはまるブール値などです。このプロパティをグラフの括弧に入れると、正規表現はそれが真かどうかをチェックします:

/^\p{ASCII}+$/u.test('abc ')//
/^\p{ASCII}+$/u.test('ABC@ ')//
/^\p{ASCII}+$/u.test('ABC ')//

ASCII_Hex_Digitは、文字列に有効な16進数のみが含まれているかどうかを確認する別のブール型プロパティです。

/^\p{ASCII_Hex_Digit}+$/u.test('0123456789ABCDEF ')///^\p{ASCII_Hex_Digit}+$/u.test('h')//

他にも多くのブール型プロパティがあり、大文字、小文字、White_Space、アルファベット、絵文字など、グラフの括弧内に名前を追加するだけで確認できます。

/^\p{Lowercase}$/u.test('h ')//
/^\p{Uppercase}$/u.test('H ')//
/ ^ \ p {絵文字} + $ / u.test( 'H')//
/ ^ \ p {絵文字} + $ / u.test( '')//

これらのバイナリプロパティに加えて、特定の値に一致するUnicode文字プロパティをチェックできます。この例では、文字列がギリシャ文字またはラテン文字で書かれているかどうかを確認します。

/^\p{Script=Greek}+$/u.test('ελληνικά ')//
/^\p{Script=Latin}+$/u.test('hey ')//

プロポーザルで直接使用できるすべてのプロパティの詳細をご覧ください。

文字列に抽出する必要のある数字が1つしかない場合、/ \ d + /はそれを行う必要があります。

'テスト123123329'.match(/ \ d + /)
//配列["123123329"]

メールアドレスと一致

単純なアプローチは、\ Sを使用して、@記号の前後にスペース以外の文字をチェックすることです。

/(\S+)@(\S+)\.(\S+)/
/(\S+)@(\S+)\.(\S+)/.exec('copesc@gmail.com ')
//["copesc@gmail.com "、" copesc "、" gmail "、" com "]

ただし、これは単純な例ですが、多くの無効な電子メールがこの正規表現で満たされているためです。

二重引用符の間のテキストをキャプチャする

二重引用符で囲まれたものを含む文字列があり、そのコンテンツを抽出するとします。

最適な方法は、キャプチャグループを使用することです。これは、マッチの開始と終了が ""であることがわかっているためです。ターゲットを簡単に設定できますが、結果からこれらの引用符を削除することもできます。

結果に必要なものを見つけます[1]:

const hello = 'Hello "nice flower"'
const result = /"([^']*)"/.exec(hello)
// Array ["\" nice flower \ ""、 "nice flower"]

HTMLタグ内のコンテンツを取得する

たとえば、spanタグ内でコンテンツを取得し、タグ内で任意の数の引数を許可します。

/]*>(.*?)<\/span>/
/]*>(.*?)<\/span>/.exec('test ')
// ヌル
/ ] *>(。*?)<\ / span> /。exec( ' test ')
// [" test "、 "test"]
/]*>(.*?)<\/span>/.exec(' test  ')
// [" test "、 "test"]
JavaScriptの学習に興味がありますか? jshandbook.comで無料の電子ブックを入手