正規表現 基礎

Regex Golf 楽しいです。正規表現クイズ楽しいです。

和田です。今回は冒頭の通り、正規表現についてです。正規表現は使いこなせれば大変強力な武器になりますが、使い所を誤ると何を書いているのかわからない、「スパゲッティ表現」になってしまうので注意が必要です。

今回紹介する構文

基礎ということで基本的な構文です。

なお、言語は JavaScript を想定していますが、言語によって大きく変わるものではないので、大体の言語で大体そのまま使えると思います。使えなかった場合、該当言語のリファレンスを参照下さい。

  • ^ - 行頭を表す
  • $ - 行末を表す
  • x|y - x または y
  • () - グループ
  • [] - 範囲
  • * - 0回以上繰り返す
  • + - 1回以上繰り返す
  • {n,m} - 指定回数繰り返す
  • ? - 0または1回現れる
  • \X - メタ文字

行頭・行末を表す

abac  
babe  
accede  
caba  
dace  
adead  
efbad  
faded  

上記のような文字列があった場合に、 a から始まっている文字列を取得する正規表現は ^a になります。また、 a で終わっている文字列を取得する正規表現は a$ になります。

上記のような文字列があった場合に a から始まっている、または終わっている文字列を取得する JavaScript の正規表現は以下のようになります。

new RegExp('^a');  
new RegExp('a$');  
// または
/^a/
/a$/

グループ 及び x または y

bone to be wild  

上記の文字列の bonewild にマッチさせたいとき、は次のようにします。

new RegExp('(bone|wild)');  
// または
/(bone|wild)/

()| を合わせることにより、 () の中の | で区切られたどれかに一致します。

範囲

abcd1efg  
ab8cdefg  
abcde7fg  
abcdefg5  
abcde3fg  
4abcdefg  

上記の文字列中の数値を取得したい場合の JavaScript での正規表現は以下のようになります。

new RegExp('[0-9]');  
// または
/[0-9]/

[0-9]」は、「[]」も含めて正規表現です。

意味合いは 0から9までの全ての数字 になり、次の正規表現と等価です。

new RegExp('(0|1|2|3|4|5|6|7|8|9)');  
// または
/(0|1|2|3|4|5|6|7|8|9)/

[] は数字だけではなく、文字にも適用することができます。

マッチのために使用する文字コードが1ずつ増えていく、と考えるとわかりやすいかもしれません。

new RegExp('[a-c]');  
new RegExp('(a|b|c)');  

上記の2つは等価です。ただし注意点としては、 aA という文字は文字コードが別になるため、何も考えずにやると一致しません。

new RegExp('[a-c]');  
// と
new RegExp('[A-C]');  
// は別の文字にマッチする
// その為、[a-c]も[A-C]もマッチさせたい場合は以下のようにする
new RegExp('[a-cA-C]');  

別の注意点としては2桁の数字の (例えば 19) をマッチさせたいとして、 [0-90-9] としてもマッチしません。

その場合、 [0-9][0-9] と表現する必要があります。

繰り返し

先の2桁の数字をマッチさせたい場合、 [0-9][0-9] とする必要があるとしましたが、繰り返し表現を使用すれば解決します。

new RegExp('[0-9][0-9]');  
new RegExp('[0-9]*');  

上記で2桁の数字にマッチさせることができたと思いますが、数値がなくてもマッチしてしまっていると思います。

これは * は 「0回以上繰り返す」 文字にマッチするようになっているからです。

その為必ず数値が現れたときだけマッチさせる場合は以下のようにするとより良いです。

new RegExp('[0-9]+');  

ただしこれも完璧ではありません。2桁を超える数字にもマッチしてしまうからです。

+ は 「1回以上繰り返す」 文字にマッチするようになっているからです。

必ず2桁の数値にのみマッチさせたい場合は以下のようにするのがベストでしょう。

new RegExp('[0-9]{2}');  

{n} は 「n回繰り返す」 というマッチ条件です。

ここまで紹介してきた繰り返しだと、「1〜3桁の数字にマッチしたい」と言った場合に対応できません。この場合は次のようにします。

new RegExp('[0-9]{1,3}');  

{n, m} は、「n回以上m回以下繰り返す」というマッチ条件です。また、 m については省略が可能で

new RegExp('[0-9]{2,}');  

上記のようにすれば、「2回以上繰り返す」数値にマッチします。

なお、以下は等価になります。

new RegExp('[0-9]{1,}');  
new RegExp('[0-9]+');  
// 及び
new RegExp('[0-9]{0,}');  
new RegExp('[0-9]*');  

ここまで紹介してきた繰り返しで、全ての繰り返しに対応できると思いますが、「0〜1回」というマッチ条件の場合は ? を使うと短くなります。

// 以下は同じ
new RegExp('m{0,1}other');  
new RegExp('m?other');  

これで、 mother または other にマッチします。

メタ文字

メタ文字は、頻出の文字範囲を表す省略形のようなものです。

例えば以下は同じです。

new RegExp('[0-9]');  
new RegExp('\d');  
//
new RegExp('[a-ZA-Z0-9_]'); // 英数とアンダースコア  
new RegExp('\w');  

また、通常のプログラムのように改行コードや、タブ文字を表す場合にも使用します。

new RegExp('\r?\n');  // 改行コード  
new RegExp('^\t+');   // 行頭にある1つ以上のタブ  

今回はここまで。次回は発展編と題してちょっと高度なことをしてみたいと思います。