正規表現とは文中からある文字列のパターンを見つけるために使用される文字列や記号の組み合わせのことです。
正規表現とは対象の文字列に左から右にマッチするパターンのことを言います。 "Regular expression" (正規表現)という言葉は "regex" や "regexp" などと一言で言い表すことがあります。 正規表現を使うことで文字列の置換・検証・抽出などを行うことが可能です。
アプリケーション中において、ユーザがユーザ名を決めるときに 守るべきルールを定義したいとしましょう。 ユーザ名には文字・数字・アンダースコア・ハイフンが使用可能であるとします。 また、ユーザ名が単調にならないように文字数にも制約を設けるものとします。 この場合、次のような正規表現でユーザ名を検証することができます。
この正規表現によって john_doe, jo-hn_doe, john12_as
などは許容されることになります。
一方で Jo
は大文字を含む上に短すぎるため許容されません。
文中から特定の文字列を検索する時の正規表現は単なる文字の並びとして表されます。
例えば the
という正規表現は t
という文字のあとに h
が続き、さらに e
が続くものだと
解釈されます。
"the" => The fat cat sat on the mat.
123
という正規表現は 123
という文字列にマッチします。
正規表現は正規表現の文字列と入力文字列を1文字ずつ比較しながらマッチングを行います。
また大文字と小文字は区別されるため、 The
は the
にはマッチしません。
"The" => The fat cat sat on the mat.
メタ文字は正規表現の構成要素として使用される文字のことです。 メタ文字はそれ自身が示す文字を表すものではなく、特別な解釈がなされます。 一部のメタ文字は角括弧内に記述されることで特別な意味を持つものもあります。 メタ文字には次のようなものがあります。
メタ文字 | 説明 |
---|---|
. | ピリオド。改行を除く任意の1文字にマッチ。 |
[ ] | 文字集合。角括弧内の任意の文字にマッチ。 |
[^ ] | 否定文字集合。角括弧内に含まれない任意の文字にマッチ。 |
* | 直前の文字の 0 個以上の並びにマッチ。 |
+ | 直前の文字の 1 個以上の並びにマッチ。 |
? | 直前の文字がオプションであるとみなす。 |
{n,m} | 括弧でくくる。直前の文字が n 個以上 m 個以下続く場合にマッチ。 |
(xyz) | 文字グループ。 xyz という文字列がその順に現れる場合にマッチ。 |
| | 選言。記号の前後の文字列どちらかにマッチ。 |
\ | 次に来る文字をエスケープする。予約語 [ ] ( ) { } . * + ? ^ $ \ | にマッチ。 |
^ | 入力値の開始にマッチする。 |
$ | 入力値の終了にマッチする。 |
ピリオド .
は最もシンプルなメタ文字の例です。
メタ文字 .
は任意の 1 文字にマッチします。
キャリッジリターンと改行にはマッチしません。
例えば .ar
は任意の文字の後に a
と r
が続く文字列にマッチします。
".ar" => The car parked in the garage.
文字集合は文字クラスとも呼ばれます。
文字集合を指定するには角括弧でくくります。
文字の範囲を指定するにはハイフンを使用します。
角括弧内の文字の記述順はマッチングには関係ありません。
例えば [Tt]he
という正規表現は大文字 T
または小文字 t
の後に h
, e
が続く文字列を表します。
"[Tt]he" => The car parked in the garage.
文字集合内でのピリオドは文字としてのピリオドを表します。
ar[.]
という正規表現は a
という文字のあとに r
が続き、さらに .
という文字が続く文字列を表します。
"ar[.]" => A garage is a good place to park a car.
通常キャレットは文字列の開始を意味するメタ文字ですが、角括弧内で最初に使用されると
文字集合を否定する意味を持つようになります。
例えば [^c]ar
という正規表現は c
以外の任意の文字列の後に
a
, r
が続く文字列を表します。
"[^c]ar" => The car parked in the garage.
+
, *
, ?
はパターンが何回続くのかを指定するためのメタ文字になります。
これらのメタ文字は異なるシチュエーションで異なる振る舞いをします。
シンボル *
は直前の文字が 0 個以上続くパターンにマッチします。
a*
という正規表現は小文字の a
が 0 個以上続くことを意味します。
しかし文字集合またはクラスの後に現れた場合はその文字集合すべてが続くことを意味します。
例えば [a-z]*
という正規表現は行内の任意の小文字の列を表します。
"[a-z]*" => The car parked in the garage #21.
シンボル *
はメタ文字 .
と合わせて .*
のように使用することで
任意の文字列を表現できます。
またスペースを表す \s
と併用することで空白文字を表現できます。
例えば \s*cat\s*
という正規表現は 0 個以上のスペースの後に
小文字の c
, a
, t
が続き、その後に 0 個以上のスペースが続きます。
"\s*cat\s*" => The fat cat sat on the concatenation.
シンボル +
は直前の文字が 1 個以上続くパターンにマッチします。
例えば c.+t
という正規表現は小文字の c
の後に
任意の 1 文字以上が続き、さらに t
が続くことを意味します。
この t
は、その文における最後の t
がマッチします。
"c.+t" => The fat cat sat on the mat.
正規表現におけるメタ文字 ?
は直前の文字がオプションであることを意味します。
すなわち直前の文字が 0 個または 1 個現れることを意味します。
例えば [T]?he
という正規表現は大文字の T
が 0 個または 1 個出現し、
その後に小文字の h
, e
が続くことを意味します。
"[T]he" => The car is parked in the garage.
"[T]?he" => The car is parked in the garage.
このt
は、その文における最後のt
であることが明確である必要があります。
正規表現における括弧は数量子とも呼ばれますが、文字列がいくつ現れるかを示すために使用されます。
例えば、[0-9]{2,3}
という正規表現は 2 桁以上 3 桁以下の数字
(0 から 9 の数字で表された文字列)にマッチします。
"[0-9]{2,3}" => The number was 9.9997 but we rounded it off to 10.0.
2つ目の数値は省略できます。
例えば [0-9]{2,}
という正規表現は 2 桁以上の数字を意味します。
カンマも省略することができ、その場合 [0-9]{3}
という正規表現はちょうど 3 桁の数字を意味します。
"[0-9]{2,}" => The number was 9.9997 but we rounded it off to 10.0.
"[0-9]{3}" => The number was 9.9997 but we rounded it off to 10.0.
文字グループは括弧 (...)
内にパターンを記述してグループ分けをするために使用します。
前述の通り、正規表現においては数量子を文字の後に置いた場合は
その直前の文字の繰り返しを意味します。しかし、文字グループの後に数量子を置いた場合は
文字グループ全体が繰り返すことを意味します。
例えば、 (ab)*
という正規表現は "ab" という文字列の 0 個以上の繰り返しにマッチします。
文字グループ内では選言 |
も使用することができます。
例えば、(c|g|p)ar
という正規表現は小文字の c
, g
, p
のいずれかの後に
a
が続き、さらに r
が続くことを意味します。
"(c|g|p)ar" => The car is parked in the garage.
正規表現における縦棒 |
は選言として使用されます。
選言は複数の正規表現からなる条件式のようなものです。
もしかすると文字集合と選言が同じものと感じるかもしれません。
この 2 つの大きな違いは文字集合は文字単位で評価されるのに対して選言は正規表現単位で評価されます。
例えば (T|t)he|car
という正規表現は大文字の T
または小文字の t
の後に
小文字の h
, e
が続くか、または小文字の c
の後に a
, r
が続くことを意味します。
"(T|t)he|car" => The car is parked in the garage.
バックスラッシュ \
は正規表現内で次に来る文字をエスケープするために使用されます。
これを使うと予約語 { } [ ] / \ + * . $ ^ | ?
を
記号として指定できるようになります。
例えば .
という正規表現は改行を除く任意の文字として使用されますが、
(f|c|m)at\.?
という正規表現では .
自体にマッチします。
この正規表現は小文字の f
, c
または m
の後に小文字の a
, t
が続き、
さらに .
が 0 個または 1 個続きます。
"(f|c|m)at\.?" => The fat cat sat on the mat.
正規表現内でマッチング文字列の開始または終了であることをチェックするために
アンカーを使うことができます。
アンカーには 2 種類あり、1 つ目が開始を表すキャレット ^
、
2 つ目が終了を表すドル記号 $
です。
キャレット ^
は文字列の開始かどうかを調べるために使用します。
次の正規表現 ^a
は入力文字列 abc
に対して(a が開始文字列なら)a
にマッチします。
しかし ^b
という正規表現は前の文字列に対してはどれにもマッチしません。
"b" は abc
という入力文字列の開始ではないからです。
他の例を見てみます。^(T|t)he
は大文字の T
または小文字の t
から始まる文字列で
その後に小文字の h
, e
が続くことを意味します。
"(T|t)he" => The car is parked in the garage.
"^(T|t)he" => The car is parked in the garage.
ドル記号 $
は文字列の終了かどうかを調べるために使用します。
例えば (at\.)$
という正規表現は小文字の a
の後に
小文字の t
が続き、最後は .
で終わることを意味しています。
"(at\.)" => The fat cat. sat. on the mat.
"(at\.)$" => The fat cat. sat. on the mat.
正規表現ではよく使われる文字集合に対して短縮表記が提供されており、 便利なショートカットとして使用できます。 短縮表記には次のようなものがあります。
短縮表記 | 説明 |
---|---|
. | 改行を除く任意の文字 |
\w | 英数字にマッチ: [a-zA-Z0-9_] |
\W | 英数字以外にマッチ: [^\w] |
\d | 数字にマッチ: [0-9] |
\D | 数字以外にマッチ: [^\d] |
\s | スペースにマッチ: [\t\n\f\r\p{Z}] |
\S | スペース以外にマッチ: [^\s] |
先読みと後読み(前後参照とも呼ばれます)は 非キャプチャグループ
(パターンのマッチングはするがマッチングリストには含まれない)という
特殊な扱いがなされる機能です。
前後参照はあるパターンが別のあるパターンよりも先行または後続して現れることを示すために使用されます。
例えば入力文字列 $4.44 and $10.88
に対して $
に続く全ての数字を取得することを考えます。
そのためには (?<=\$)[0-9\.]*
という正規表現を使用します。
これは $
に続き .
を含む全ての数字を指すことになります。
次のような前後参照が正規表現で使用されます。
記号 | 説明 |
---|---|
?= | 肯定的な先読み |
?! | 否定的な先読み |
?<= | 肯定的な後読み |
?<! | 否定的な後読み |
肯定的な先読みはあるパターンが注目しているパターンよりも後続していることを示すための機能です。
マッチングの結果には注目しているパターンだけが含まれます。
肯定的な先読みを定義するには括弧を使用します。
その括弧の中で疑問符と等号を合わせて (?=...)
のようにします。
先読みのパターンは括弧の中の等号の後に記述します。
例えば (T|t)he(?=\sfat)
という正規表現は小文字の t
か大文字の T
のどちらかの後に h
, e
が続きます。
括弧内で肯定的な先読みを定義していますが、これは The
または the
の後に
fat
が続くことを表しています。
"(T|t)he(?=\sfat)" => The fat cat sat on the mat.
否定的な先読みはあるパターンが後続しない全てのマッチング文字列を取得するために使用します。
否定的な先読みは肯定的な先読みと同じように定義しますが、 =
の代わりに
!
を使うところが唯一の違いで、(?!...)
と記述します。
次の正規表現 (T|t)he(?!\sfat)
について考えてみます。
これはスペースを挟んで fat
が後続することがない全ての The
または the
を得ることができます。
"(T|t)he(?!\sfat)" => The fat cat sat on the mat.
肯定的な後読みは特定のパターンが先行するような文字列を得るために使用します。
定義の仕方は (?<=...)
とします。
例えば (?<=(T|t)he\s)(fat|mat)
という正規表現は
The
または the
の後に続く全ての fat
または mat
が取得できます。
"(?<=(T|t)he\s)(fat|mat)" => The fat cat sat on the mat.
否定的な後読みは特定のパターンが先行しない全ての文字列を得るために使用します。
定義の仕方は (?<!...>)
とします。
例えば (?<!(T|t)he\s)(cat)
は The
または the
に続いていない全ての cat
が取得できます。
"(?<!(T|t)he\s)(cat)" => The cat sat on cat.
フラグは修飾子とも呼ばれ、正規表現の結果を修正するために使用されます。 フラグは任意の順序・組み合わせで使用でき、正規表現では必要不可欠な機能です。
フラグ | 説明 |
---|---|
i | 大文字・小文字を区別しない: マッチングで大文字・小文字が区別されなくなる |
g | グローバル検索: 入力文字列の全マッチ列を検索する |
m | 複数行: 複数行をマッチさせるためのアンカー |
修飾子 i
は大文字・小文字を区別したくないときに使用します。
例えば /The/gi
という正規表現は大文字の T
の後に小文字の h
, e
が続くという意味ですが、
最後の i
で大文字・小文字を区別しない設定にしています。
文字列内の全マッチ列を検索したいのでフラグ g
も渡しています。
"The" => The fat cat sat on the mat.
"/The/gi" => The fat cat sat on the mat.
修飾子 g
はグローバル検索(最初のマッチ列を検索する代わりに全マッチ列を検索する)を
行うために使用します。
例えば /.(at)/g
という正規表現は、改行を除く任意の文字列の後に
小文字の a
, t
が続きます。正規表現の最後にフラグ g
を渡すことで、
最初のマッチだけではなく(これがデフォルトの動作です)、入力文字列内の全マッチ列を検索するようにしています。
"/.(at)/" => The fat cat sat on the mat.
"/.(at)/g" => The fat cat sat on the mat.
修飾子 m
は複数行でマッチさせたいときに使用します。
前述で (^, $)
という入力文字列の開始と終了を示すためのアンカーについて説明しましたが、
フラグ m
は複数行でマッチさせるためのアンカーとして使用できます。
例えば /at(.)?$/gm
という正規表現は小文字の a
, t
に続き、改行を除く
任意の文字が 0 個または 1 個続くという意味ですが、
フラグ m
を渡すことで入力文字列の各行でパターンを検索させることができます。
"/.at(.)?$/" => The fat cat sat on the mat.
"/.at(.)?$/gm" => The fat cat sat on the mat.
- イシューを発行する
- 修正をプルリクエストする
- ドキュメントを普及させる
- 作者に直接連絡を取る: [email protected] または
MIT © Zeeshan Ahmad