正規表現技術入門 第一章 入門 まとめ
はじめに
正規表現は使用してる言語やフレームワーク、アプリなどで記述の仕方や使える関数が違うのでここでは詳しく説明することはありません。
記事の目的
正規表現を触ったことのない人、少し触った事がある人の知識を増やす。
正規表現の内容を大雑把に把握することでいつでもググれる知識を作り出す。
参考資料
正規表現技術入門
出版社: 技術評論社
参考資料の内容
第一章 [入門]正規表現
第二章 正規表現の歴史
第三章 プログラマのための一歩進んだ正規表現
第四章 DFA型エンジン
第五章 VMエンジン
第六章 正規表現エンジンの三代技術動向
第七章 正規表現の落とし穴
第八章 正規表現を超えて
今回まとめる章
第一章[入門]正規表現のみ
知っておくと後の説明をスラスラ読める単語集
正規表現
字列のパターンを記述するための表現式のこと構成要素
数式における数などをのこと演算子
数式における足し算や掛け算などのこと量指定子
繰り返しをする演算子のことメタ文字
正規表現する際に使われる特別な文字リテラル
特別な意味をなさない文字グループ化
キャプチャ
マッチした文字列の保存構文(シンタックス)
メタ文字とリテラルを合わせて書いた文のこと正規表現エンジン
正規表現マッチング処理のこと。エンジンが変われば構文や機能も変わるマッチする
与えられた文字列が正規表現が表しているパターンに入っている場合、正規表現は与えられたもじにマッチするという。サブパターン
()で括った正規表現をサブパターンというサブマッチ
サブパターンでマッチすることをサブマッチというシンタックスシューガー
既存の構文などを別の構文や記法で記述できるようにしたもの完全一致
文字列全体がマッチすること前方一致
文字列の先頭辞にマッチすること後方一致
文字列の接尾辞にマッチすること部分一致
文字列の部分文字にマッチすることスター:累乗演算や優先順位を明示的に用いる時に使用される「*」のこと
正規表現の基本三演算
-
パターン連結
「r」と「s」の二つの正規表現があった場合この二つをつなげて正規表現「rs」と表す事ができる。「rs」は「r」の後に「s」が続いたパターンにマッチする。 -
パターンの選択
「r」と「s」の二つの正規表現を「|」で並べた正規表現「r|s」は「r」というパターンもしくは「s」というパターンを表す。「[a-z]」はaからzまでの文字選択を行える。 -
パターン繰り返し
「*d」は任意の長さの文字列を「[A-Za-z]*」は任意長のアルファベットを示す。
基本構成はこの基本三演算を組み合わせたものになる。
正規表現のシンタックスシューガー
上の基本三演算では複雑な式になってしまうのでシンタックスシューガーを用いることになった。
- プラス演算 + 一回以上の任意回の繰り返し
- 疑問符 ? 0か1回繰り返か
- 範囲量指定子 {n,m} nからm回の繰り返し
- ドット . 任意の一文字
- 文字クラス [0-9] 表現したい文字を[]で囲む 文字順番はASCllコード順
- エスケープシーケンス \でバックスペースやメタ文字を表現する
それに加え特定の文字を略記号で表現できる。これは言語やフレームワークによって違うからもしれないので要注意 - アンカー 文字の位置によってをマッチする記法 行頭やテキスト先頭など
演算子の結合順位
繰り返し>連結>選択
それぞれ累乗、掛け算、足し算と同じ優先順位のイメージを持つと捉えやすい
()*で囲むと優先的に評価することを明示的に指定できる。これをグループ化という
例 (hoge|huga)*
キャプチャ
サブマッチしたものを抜き出す事をキャプチャという
キャプチャ方法&手段
- 順番でキャプチャ
RuByなどではキャプチャした順番に取得できる機能がある
例 2000/9/12/ を (\d{4})/(\d{2})/(\d{2})でマッチさせると
(2000,9,12)と順番にキャプチャする事ができる - 名前付きキャプチャ
サブパターンに名前をつける事ができる
例
s = '2016-05-08'
if /(?<year>\d+)-(?<month>\d+)-(?<day>\d+)/ =~ s
# =~は名前付きキャプチャがそのままローカル変数になる
puts "year: #{year}, month: #{month}, day: #{day}"
# => year: 2016, month: 05, day: 08
end
-
grepキャプチャ
エディッタとgrep検索と同じでマッチしたらその文字列を取得するような機能が備わっている言語が多いい -
キャプチャの候補を減らす
グループ化はしたいけどキャプチャしたくない時は「?:」を使うこともできる。 -
キャプチャは左が優先
例
'abcde'.match(/abc|abcd/)
# =>"abc"
- 文字列置換
基本的に文字列置換はサポートされてる事がほとんどなのでよく言語やフレームワークなどを確認する事。有名なところではUnixのsend
がある
先読み 後読み
- 先読み
与えられたパターンが直後に来る位置にマッチする機能 - 後読み
与えられたパターンが直前に来る位置にマッチする機能
例 1000000を先読みで表現した(?<=\d)(?=(\d{3})+($|\D))
で処理するとカンマを挿入したい位置でマッチする。処理内容は「左側に数字、右側に数字以外の文字か行末が来るまで3行の数字繰り返しが続く位置」にマッチする。
AND演算 共通部分 積
先読みで積(and)を表現することもできる
例 「fuga」「hoge」「piyo」という三つの文字列を含むような文字列を正規表現でマッチしたいと思った時、通常の書き方では
.\*hoge\.\*fuga\.\*piyo\.\*|.\*hoge\.\*piyo\.\*fuga\.\*|\.\*fuga\.\*hoge\.\*piyo\.\*|.\*fuga\.\*piyo\.\*hoge\.\*|\.\*piyo\.\*hoge\.\*fuga\.\*|\.\*piyo\.\*fuga\.\*hoge\.\*
となってしまうが、先読みを使えば
(?=.*hoge.*)(?=.*fuga.*)(?=.*piyo.*).*
で表現できる
先読み部分(?=.*hoge.*)(?=.*fuga.*)(?=.*piyo.*)
は直後に「fuga」「hoge」「piyo」含む文字列が来る位置にマッチするのでこの先読読み取り部分の後に続く.*
は必ず「fuga」「hoge」「piyo」を含む文字列全体にマッチする。
このように複数の正規表現に同時にマッチするパターンを正規表現のAND演算や共通部分、積といいう。
否定先読み
- 否定先読み
表現するパターンが直後に来ない位置にマッチする
例 否定先読みで表現した(?!3869)\d{4}
は3896以外の数字四桁とマッチする
再起
一部の言語では再起が使える。
-
再起の説明
PCREライブラリでは再起演算は(?R)とされ正規表現全体にマッチします。
例えば
A(?R)|B
という正規表現は展開すると
A(A(?R)|B)
と表現できます。これに引き続き展開を続けると
A(A(A(A(A(A(...)|B)|B)|B)|B)|B)|B
となります。
これはAが0回以上続いてBで終わるとパターン表現しています。 -
再起じゃないと表現できないパターン
四則演算が使える数式を表現すると以下のようになる
(\d+|\((?R)\))([-+*/](\d+|\((|\((?R)))*
後方参照
キャプチャによって取得した部分文字列をその表現の中で参照すること
例<(h1|h2)>.*<\/\1>
と表現すると<h1></h1>
で囲んであるものもしくは<h2></h2>
で囲んであるものをマッチする。<\/\1>
の\1
は最初にマッチした内容を参照する。
基本三演算では表現できないパターン
- 四則演算のような再起を使わなければ表現できないもの
- 開始タグと終了タグの生合成をとる後方参照を使うパターン
どちらも可読性が悪くなってしまう事が多いいのでなるべく使用を避けること。