正規表現入門
はじめに
つぁいにゃお氏が始めて以来, お祭り騒ぎの様になっている The 言語 Advent Calendar 2018 の最後の記事を書ける機会を頂けた事を非常に嬉しく思っている。 今回解説する正規表現は一応言語であるが, 一般に言語というより文字列全般の処理に使われる表現方法である。 テーマから外れるかと危惧したが, 同じアドベントカレンダーに形態素解析やっている人がいるのできっと許されるであろう。 また, 私事にて投稿までの時間が限られている為, あらかじめ扱う範囲を明示しておく。
メタ文字とリテラル
アンカー(行頭, 行末)
文字クラス(否定クラス)
選択
追記または 次の記事で触れていきたい範囲
正規表現誕生の経緯
正規表現のトレンド
量指定子(+最小量指定子)
量指定子(最大量指定子, アトミックグループ)
修飾子(i/g等)
正規表現の問題点(バックトラック)
非包含オペレータ
余談 -ReDos-
時間の許す限りの修正, 推敲は加えていくが誤字, 脱字は含まれているであろう。 また, 注意として 筆者は出典を1ヶ月読み込んで基礎を抑えたほぼ素人である為, 間違った記述が含まれている可能性がある。
本記事を読んで気づいた事, ご指摘はお寄せ頂けると幸いである。 別記事による追補, 修正などに役立てさせていただく。
対象読者
正規表現とは? ~ 聞いたことあるし多少使える!(一ヶ月前の私の様な!)といった人に向けている。
正規表現とは
正規表現という言葉を聞いたことはあるだろうか。 数学科, 形式言語理論の人なら"正則表現"の方が馴染み深いかもしれない。
この記事で扱われる正規表現はテキスト処理における強力なツールであり, 熟練者が組み立てた正規表現の文字列とそれがもたらす効果は 正規表現の世界を知らない人間からは魔法の様に見える...ものである。
\b(0[5789]0-?\d\d\d\d-?\d\d\d\d)\b
この記事を読み終えれば複雑怪奇な文字列の塊を理解出来る様になるだろう。
私が読むべき記事ではないのでは?と感じたあなた, あなたの為にこの記事は書かれている。
てっとり早く試したい?という困った人はこちらへ
例示
あなたは Winows or Unix のユーザであり HDDのどこかにある拡張子がmp4のファイルを探している。 拡張子はmp4だがファイル名は忘れてしまった。 あなたはファイルの検索欄にこう打ち込む。
*.mp4
数秒後には関係がないものも含めて拡張子がmp4のファイルのリストが表示される...
これは正規表現ではない(ワイルドカード等と呼ばれる)。 ここでの*(アスタリスク)には任意のものにマッチするという意味がある。 つまり, 任意の文字で始まりリテラルの ".txt" で終わるファイルを探す。 しかしながら, ワイルドカードには表現力の限界がある(他, 数種類の特殊文字が用意されてはいるが)。
ワイルドカードはファイルの検索には十分使えるがテキスト全般(コード, 散文, 単語リスト, HTML) を処理するにはいささか力不足であった。
そこで汎用的に使える表現方法と能力を持ったパターン言語が出てきた。 このパターン言語とパターン自体を正規表現と呼ぶ。
認知
ざっくりとどういった物を扱おうとしているか掴めただろうか。
ここから正規表現の本格的な使い方に足を踏み入れていく。
メタ文字とリテラル
まず, 正規表現は2種類の文字の組み合わせで構成される。 メタ文字とリテラルである。
メタ文字とはワイルドカードの * の様に特殊な性質を持つ文字である。 その他の文字はリテラルと呼ばれる通常のテキスト, 文字である。 例えばリテラルのみの
cat
は単純なプレーンテキスト検索になるので
c a t
の文字列が含まれている部分すべてにマッチする。
つまり,
vacation
catring
などにもマッチする。
アンカー(行頭, 行末)
しかし, cat を捕まえようとして
catastrophe
をマッチさせたりしたくないだろう。 そこでアンカーを使う。
^ と $ は行頭と行末を指定するメタ文字である。
実践
学んだ事を早速試してみよう。
>ここ<のテキストから "cat" にマッチする正規表現を作りたい。 ただし, くれぐれも連結させたり破滅させたりしないように。
正解は こうだ
^cat$ は行頭があり, 次にc, その次にa, そしてtに, そして行末となっている部分にマッチする。
文字クラス(否定文字クラス)
japanese という単語を見つけたいが japanise という綴りのものも見つけたいとする。
文字クラスを使えば特定の文字だけを指定できる。
japan[ei]se と書き表せば両方満たす正規表現になる。
また, [a-z] と書き表せば"a"から"z"の文字列全てにマッチする。
[123456] 等と書いたり
[A-Z1-3] 等と書くことも可能だ。
-(ダッシュ)がメタ文字になるのは文字クラスの略記法を使うときだけだ。
-をマッチの対象にしたければ [-a-z0-9] とすれば良い。
!や?も文字クラスの中では大人しくなる事を覚えておこう。
つまり [!?-a-z0-3] でマッチする文字列は "!" , "?" , "a" から "z" までと "0" から "3" までだ
なお, [^1-6] と書き表せば "1" から "6" 以外の何かにマッチする正規表現を書ける。
実践
-->ここ<--のテキストで "calendar" をマッチさせよう。 しかし "calender" にもマッチさせたい。
正解は こうだ
---->ここ<----のテキストのうち "4" と "9" 以外にのみマッチさせたい
正解は こうだ
メタ文字
.(ドット)は任意の文字にマッチする文字クラスである。 年月日の表記が "18/11/25", "18.11.25", "18-11-25" などと揺れている時に使える。
上記の例であれば 18.11.25 と書けば全てにマッチする。
選択
|(パイプ)は, または を表すメタ文字である。
japan(i|e)se と japanise|japanese は等価である。
共に "japanese", "japanise" にマッチする。
"1st", "first" にマッチさせたければ
(1|fir)st と書き表せば良い。
量指定子
"column" と "colum" にマッチする正規表現させたい。
この場合 ? を使う。前方の文字の個数を, 1つ認める(0も許容する)。
column?
- を使えば任意の数を認めることが出来る(0も許容する)。
- は1つは必須である(それ以上も許容する)。 また {min,max} と書き表せば {min, max} 回の文字の繰り返しを指定できる。
出典
詳説 正規表現 第4版
あとがき
もろもろ書きたいことあったのだけど一旦ここで筆を置くことにする。
時間をかければもっと高い完成度で記事を書き上げる事が出来たはず。
インプットよりアウトプットの方が難しいのだなと良い勉強になった。