正規表現というと「記号が多く意味不明・難しそう・読めない──」といった印象を持っていたのですが、「簡単な正規表現はいつでも使えるようにしておきたい」という思いから段階を分けて学んでみたところ少しづつ理解が進んでいきました。
まずは「文字・文字クラス・量指定子」の役割と関連するメタ文字に的を絞り、理解しやすい順序でおさらいしてみたいと思います。
テスト環境 PHP 7.3.2 UTF-8
正規表現について
正規表現では「パターン」で文字列を表現する
PHPの正規表現では「/」で囲まれた「パターン」と呼ばれる部分で文字列を表現します。
パターンでよく使われるものの1つに「文字と文字量を指定したもの」があり、さらにそれを組み合わせたりすることで様々な文字列を表現します。
この「文字と文字量を指定したもの」を構成する「文字・文字クラス・量指定子」について理解しやすい順に見ていきます。
パターンを囲む「/」はデリミタと呼ばれ、主に「/(スラッシュ)」が使われますが「#」や「%」等の記号が使われる場合もあります。
文字
文字Lv1:文字を直接指定する
任意の1文字を直接指定して表します。
単語を指定する場合は「特定の並びになった1文字の集まり」と考えると後々理解しやすいです。
どんな1文字にもマッチする「.(ドット)」も「文字」として扱われます。
パターン例
A | “A” にマッチ |
p | “p” にマッチ |
Apple | “Apple”(という指定した文字の並び)にマッチ |
pattern-. | “pattern-〇” にマッチ(〇は何でもOK) |
文字Lv2:選択肢とグループ化
「〇〇または△△」のようにどちらかにマッチさせたい場合は「|」で区切ります。
パターン例
Dog|Cat | “Dog” または “Cat” にマッチ |
パターンの一部を選択肢にするには波括弧で囲んでグループ化します。
グループ化は複数の文字を1つにまとめる効果があります。
パターン例:グループ化の有無による違い
Dog|Cat food | “Dog” または “Cat food” にマッチ |
(Dog|Cat) food | “Dog food” または “Cat food” にマッチ |
上の例でグループ化の有無による違いが分かると思います。
前者は “Dog” か “Cat food” の選択肢になっているので “Dog food” にはマッチしません。 後者はグループ化された “Dog” か “Cat” の選択肢に続けて ” food” が指定されているため “Dog food” または “Cat food” にマッチします。
「文字」の押さえるべき重要ポイント
- 「.(ドット)」は任意の1文字を表す
- 「〇〇|△△」選択肢
- 「(〇〇)」波括弧でグループ化
文字クラス
文字クラスLv1:文字クラスでいずれかの文字を表す
いくつかの文字が角括弧で囲まれたものを「文字クラス」といい、文字クラス内にあるいずれかの文字を表します。角括弧で囲まれた範囲を1つの文字と考えます。
「文字クラス」も前述の「文字」と同様に「文字そのもの」を表しています。
パターン例
[ABC] | “A” または “B” または “C” にマッチ |
[345] | “3” または “4” または “5” にマッチ |
文字クラスLv2:文字範囲と否定
- 「-(ハイフン)」を使って文字の範囲を表すこともできます。
- 文字クラス内の最初に「^」を書くと文字クラス内のいずれかの文字以外にマッチする「否定文字クラス」になります。
パターン例
[3-8] | “3” から “8” までのいずれかにマッチ |
[^abc] | “a”, “b”, “c” のいずれか以外の1文字にマッチ |
文字クラスLv3:よく使う文字クラスは略記法がある
使用頻度の高い文字クラスは省略して書くことができます。
decimalの “d”、wordの “w”、それぞれ大文字で否定という形になっています。
[0-9] | 半角数字の1文字 | \d |
[^0-9] | 半角数字以外の1文字 | \D |
[a-zA-Z0-9_] | 半角英数字もしくはアンダースコア1文字 | \w |
[^a-zA-Z0-9_] | 半角英数字もしくはアンダースコア以外の1文字 | \W |
「\(バックスラッシュ又は円記号)」と文字を組み合わせたものは「メタ文字」といい、特殊な意味を持っています。メタ文字は数が多いため、必要なものから順に覚えると効率よく覚えられます。今回は「“\d, \D, \w, \W” は文字クラスの略である」というところがポイントです。
「文字クラス」の押さえるべき重要ポイント
- 「[](角括弧)」に含まれるいずれか1文字を表す
- 「-(ハイフン)」で範囲を表現
- 「^」で否定文字クラス
- 文字クラスの省略型 “\d, \D, \w, \W”
量指定子
量指定子Lv1:{n,m}で繰り返し量を指定する
ここまでで解説した「文字」に対して「文字の量(繰り返し)」を指定することができます。
繰り返し量は繰り返す文字直後の波括弧内に数値で指定することができ、この部分を「量指定子」といいます。「文字・文字クラス」と「量指定子」の組み合わせでどんな文字がいくつあるのかを表現しています。
量指定子の書き方は3種類あり、それぞれ次のような意味を持ちます。
〇{n} | 〇がn回の繰り返しにマッチ |
〇{n,} | 〇がn回以上の繰り返しにマッチ |
〇{n,m} | 〇がn回以上、m回以下の繰り返しにマッチ |
パターン例
Ah{4} | “Ahhhh” にマッチ(繰り返しは直前の1文字 “h” にのみ影響する。) |
w{3,} | wが3つ以上続く場合にマッチ “www”, “wwww”, “wwwww”, …… |
Oh{2,3} | “Ohh”, “Ohhh” にマッチ |
量指定子Lv2:連続した文字の繰り返しにはグループ化を使う
通常は直前の1文字の繰り返しを表す量指定子ですが、「グループ化」を使うと連続した文字の繰り返しを表現することができます。
パターン例:グループ化の有無による違い
Dog{2} | “Dogg” にマッチ(繰り返しは “g” にのみ影響する。) |
(Dog){3} | “DogDogDog” にマッチ(グループ化された “Dog” を繰り返す。) |
グループ化は「文字Lv2」でも複数の文字を1つの選択肢にするために使ったように色々な場面で役立ちます。
量指定子Lv3:量指定子を表すメタ文字
文字クラスのときと同様に、代表的な量指定子はメタ文字で表すことができます。
〇{0,1} | 直前の文字が一つもしくは無しの場合 | ? |
〇{1,} | 直前の文字が1回以上繰り返す場合 | + |
〇{0,} | 直前の文字が0回以上繰り返す場合 | * |
パターン例
Gre?een | “Greeen”, “Green” にマッチ(3文字目の “e” が1つもしくは無し) |
(Ora)+ | “Ora” が1つ以上繰り返す場合にマッチ |
Zz* | “Z”, “Zz”, “Zzz” …… “Z(大文字)” の後に “z(小文字)” が0回以上続く場合にマッチ |
「量指定子」の押さえるべき重要ポイント
- 文字そのものを表す「文字・文字クラス」とは違い、量指定子は「文字の量」を表現している。
- 量指定子は直前の文字・文字クラスの繰り返しを指定する。
- 「{}(波括弧)」で繰り返し量を指定する
- 量指定子の代わりとなるメタ文字 “? + *”
さいごに
基本を組み合わせて幅広い表現が可能に
パターン例
G[lr]ass | “Glass” または “Grass” にマッチ 文字 + 文字クラス + 文字 |
(Type|No)[12] | “Type1”, “Type2”, “No1”, “No2” にマッチ 文字の選択肢 + 文字クラス |
([BD]ora){2,4} | “Bora” または “Dora” が2~4回繰り返す場合にマッチ 文字クラスと文字のグループ化 + 量指定子 |
No \d+ | “No ” の後に半角数字が1つ以上繰り返す場合にマッチ 文字 + 文字クラス + 量指定子 |
ここまでで紹介した「文字・文字クラス・量指定子」を組み合わせることで表現できる文字列の幅が広がったのが分かると思います。
コーディング時の検索等で使える例
テキストエディターの正規表現による検索等で使えそうな一例です。
一部本稿で紹介していない内容も含まれます──。
(\r|\n|\r\n) | すべての改行コードにマッチ \r , \n , \r\n のいずれか |
(?:\n|\r|\r\n){2,} | 改行コードが2つ以上続く場合にマッチ |
\d+ | 1文字以上の半角数字にマッチ |
sample[^ ] | 直後が半角スペースでない “sample” にマッチ |
[^ ]A | 直前が半角スペースでない “A” にマッチ |
参考リンク
PHP.net – PHP: PCRE 正規表現構文 – Manual
rubular.com : 正規表現の動作確認ができます。