正規表現

正規表現

正規表現全般に関して。 かなり正規表現素人なので、しらなくて実装依存なことを書いてしまうかもしれないけど・・・

正規表現のイメージ

正規表現は複雑な表面をもつ立体に巨大なシールを(左)端から貼り付けていくようなイメージで捉えるとわかりやすいと思う

最も単純なルール

左から正規表現がマッチするまで1文字づつ順番に進んでいく、最大マッチした時点で終わり。 逆に言うならば、最大マッチするパターンを優先的に探索する。

あまりにゆるい条件にすると、目的の文字列に到達する前にどこか変なところでマッチして終わってしまうので注意。特に?によるオプションや*によるゼロ回繰り返し

設計方針

無理に1個で書かない

なんでも一発で判定できる神業的な正規表現を書くことは難しいので、無理だと思ったら段階的に判断する方法を選んだほうが無難

否定形は処理系と組み合わせて

正規表現の構造上~にマッチしないというものを書きにくい。だからそこは処理系と組み合わせて処理したほうが利口

挟み撃ち判定は苦手

正規表現の基本は左側からの判定なので文字列ズバリではなく正規表現で正規表現を挟み撃ちにするような判定は困難。

正規表現では1文字を1単位と考えて動作する。複数文字まとめて動作させたいときは括弧をつける

?は先行する1文字(塊)をオプションにする

?は先行する1文字(塊)をオプションにする記号 オプションにするってことはあってもなくてもOKということ

hoge?moge

こうならば、hoge のケツの eがオプションになるので・・・

hogemoge
hogmoge

この両方にマッチする。

「|」は優先順位が低い

hoge|moge

の「|」は e と m の選択になっていそうだけど、実際はhoge と moge の選択として動作する

だから暗黙的に・・・

(hoge)|(moge)

こんな感じ。 これは演算子の結合強度が通常の文字並びよりもさらに低いため、一番意味的な解釈が最後に行われるから。

キャプチャ

マッチした文字列を部分的に掴んでおくことができる

キャプチャ番号の採番順序

  • 外側優先
  • 左側優先

キャプチャしない括弧

(?:hoge)

このように括弧の頭に「?:」をつけるとキャプチャ対象にならない

場所にマッチさせる

普通は文字にマッチするんですけど、正規表現には場所にマッチさせる記述もある

先頭にマッチ

ハット記号は先頭にマッチ

^hoge

なのでこれならば先頭のほげにマッチする。

hoge
ahoge

上はマッチするけど下はマッチしない。先頭っていう「位置」に続いてhogeが無いとマッチしないから

末尾にマッチ

ドル記号は末尾(行末)にマッチ

hoge$

ある文字列の左側(肯定)

解説だと先読みの肯定とか言われるやつ。キーワードを?=括弧で括るように記述

(?=hoge)

これだと

aaaahoge

に対して、hogeの左側・・・つまりaとhの境界の位置にマッチすることになる。

この動きの特徴的なところは位置にマッチなのでhoge自身にはマッチしないということ。 何かの文字列のその先にマッチする境界があった場合・・・という意味になる。だから「先読み」と呼ばれる

ある文字列の左側じゃない(否定)

解説だと先読みの否定とか言われるやつ。キーワードを?!で括るように記述する。

(?!hoge)

これは肯定の逆である文字列の左側じゃない部分にマッチする。 文字と文字の境界面なんて文字の数だけあるんで、ほとんどどこでもマッチしてしまう。 だからこれを使うときはかなり注意が必要

正規表現で否定という表現を使うのは頭を使うね。こいつはホントにこんがらがる。苦手。

部分的なヒットを利用して正規表現を動的に生成する

説明はまどろっこしいですけど使い方は簡単

^(...)\1

こう定義しておくと

abcabc

にヒットする

123123

にもヒットする

abc123

にはヒットしない

つまり括弧で括られた部分のヒット内容を\1で利用して全体の正規表現になるような正規表現ってことですハイ

繰り返し

0回以上

直前の塊のゼロ回以上の繰り返しを表現するのは

a*

アスタリスク「*」を使う この例の場合だと

aaaa
aa
a

とかにマッチする。

こいつのポイントは「無」にもマッチすること。つまり何かの起点にはこの表現は使えない

最長マッチ

アスタリスクだけの繰り返しマッチには特徴があってその時点での最長の範囲がマッチするように振る舞う。

このような文字列があって、

abcdefghijkkkkkkkjlmn

ここで、abcdefghij の部分が取りたいと思い、このような正規表現にすると

a.*j

実際には、ここまでマッチする。

abcdefghijkkkkkkkj

a に続いて .* が来た時点で取れる最長部分まで取るという挙動になる。 なので a.* まで来たときは文字列全部マッチ対象にしている。

abcdefghijkkkkkkkjlmn

それが終わって次に j が来るので最長範囲から少し戻って kjlj までが範囲となるのだ。

このようにアスタリスクにはとりあえず左側からガバーっと取ってその後で後続の条件に合致するように戻るという性質がある。

最短マッチ

アスタリスクにクエスチョンマークをつけたの繰り返しマッチには特徴があってその時点での最短の範囲がマッチするように振る舞う。

このような文字列があって、

abcdefghijkkkkkkkjlmn

ここで、abcdefghijkkkkkkkj の部分が取りたいと思い、このような正規表現にすると

a.*?j

実際には、ここまでマッチする。

abcdefghij

a に続いて .*? が来た時点で取れる最短部分まで取るという挙動になる。 なので a.*? まで来たときは0回以上の繰り返しの最短なのでこの部分になる

a

それが終わって次に j が来るので最短範囲から少し進んで abcdefghijj までが範囲となるのだ。

このようにアスタリスクににクエスチョンマークをつけると、左側からジリジリと1文字ずつ進みながら後続の条件に合致するように戻るという性質がある。

1回以上

こいつはアスタリスクと違って1個は必ず要る。

a+

指定回数

指定回数ズバリ

この場合は4回繰り返しにマッチ

a{4}

範囲指定

4~10回にマッチさせたかったら

a{4,10}

指定回数以上、以下

a{4,}
a{,4}

例文

改行を含むすべてにマッチ

[\s\S]

ドットは改行以外のすべての文字。複数行にわたるものをマッチさせようと思うと改行を含むすべての文字にマッチする正規表現が必要になる。Javascriptのようなオプションが貧弱な処理系では使える技

漢字にマッチ(Unicode処理系)

[一-龠]

このような正規表現でほとんどの漢字にマッチできる。ちょっとはみ出る部分もあるけど実用上問題なし

特定の文字列を含む文字列にヒットしない

否定形の正規表現を作りたい場合とか

^(?:(?!hoge).)*$

HTMLのスクリプトタグ部にヒット

元ねたはprototype.js

<script[^>]*>([\S\s]*?)<\/script>

コメント記法を使わずに正規表現の一部を無効化する

ある正規表現の一部分を無効化したいが、技術的制約で Perl の正規表現の拡張コメント記法が使えない場合

ケツにくっついている何でもOK部分をとりあえずコメントアウトしたい

hogehogehoge.+

コメント記法を使うと

hogehogehoge(?# .+ )

これでOK

しかしライブラリ等の関係でそれが使えない場合、とりあえず

hogehogehoge(qaswdegthyuj .+ swedrfgtyhujik)?

このように絶対にヒットしないであろう文字列で挟んでその部分をオプション指定にすることで無効化できる。

意味としては・・・

hogehogehoge に続き、絶対マッチしないであろう文字列があってもいいしなくてもいい。つまりマッチしないので、なし、なくてもいいなので結論として「ない」ということになる。

・・・と思うんだが。これがダメなパターンはちょっと自分の頭では思いつかない

タグ

regular_expression/start.txt · 最終更新: 2019-04-22 11:07 by ore