menu
書いてる野郎
orebike@gmail.com
正規表現全般に関して。 かなり正規表現素人なので、しらなくて実装依存なことを書いてしまうかもしれないけど・・・
正規表現は複雑な表面をもつ立体に巨大なシールを(左)端から貼り付けていくようなイメージで捉えるとわかりやすいと思う
左から正規表現がマッチするまで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で利用して全体の正規表現になるような正規表現ってことですハイ
直前の塊のゼロ回以上の繰り返しを表現するのは
a*
アスタリスク「*」を使う この例の場合だと
aaaa aa a
とかにマッチする。
こいつのポイントは「無」にもマッチすること。つまり何かの起点にはこの表現は使えない
アスタリスクだけの繰り返しマッチには特徴があってその時点での最長の範囲がマッチするように振る舞う。
このような文字列があって、
abcdefghijkkkkkkkjlmn
ここで、abcdefghij
の部分が取りたいと思い、このような正規表現にすると
a.*j
実際には、ここまでマッチする。
abcdefghijkkkkkkkj
a
に続いて .*
が来た時点で取れる最長部分まで取るという挙動になる。
なので a.*
まで来たときは文字列全部マッチ対象にしている。
abcdefghijkkkkkkkjlmn
それが終わって次に j
が来るので最長範囲から少し戻って kjl
の j
までが範囲となるのだ。
このようにアスタリスクにはとりあえず左側からガバーっと取ってその後で後続の条件に合致するように戻るという性質がある。
アスタリスクにクエスチョンマークをつけたの繰り返しマッチには特徴があってその時点での最短の範囲がマッチするように振る舞う。
このような文字列があって、
abcdefghijkkkkkkkjlmn
ここで、abcdefghijkkkkkkkj
の部分が取りたいと思い、このような正規表現にすると
a.*?j
実際には、ここまでマッチする。
abcdefghij
a
に続いて .*?
が来た時点で取れる最短部分まで取るという挙動になる。
なので a.*?
まで来たときは0回以上の繰り返しの最短なのでこの部分になる
a
それが終わって次に j
が来るので最短範囲から少し進んで abcdefghij
の j
までが範囲となるのだ。
このようにアスタリスクににクエスチョンマークをつけると、左側からジリジリと1文字ずつ進みながら後続の条件に合致するように戻るという性質がある。
こいつはアスタリスクと違って1個は必ず要る。
a+
この場合は4回繰り返しにマッチ
a{4}
4~10回にマッチさせたかったら
a{4,10}
a{4,} a{,4}
[\s\S]
ドットは改行以外のすべての文字。複数行にわたるものをマッチさせようと思うと改行を含むすべての文字にマッチする正規表現が必要になる。Javascriptのようなオプションが貧弱な処理系では使える技
[一-龠]
このような正規表現でほとんどの漢字にマッチできる。ちょっとはみ出る部分もあるけど実用上問題なし
否定形の正規表現を作りたい場合とか
^(?:(?!hoge).)*$
元ねたはprototype.js
<script[^>]*>([\S\s]*?)<\/script>
ある正規表現の一部分を無効化したいが、技術的制約で Perl の正規表現の拡張コメント記法が使えない場合
ケツにくっついている何でもOK部分をとりあえずコメントアウトしたい
hogehogehoge.+
コメント記法を使うと
hogehogehoge(?# .+ )
これでOK
しかしライブラリ等の関係でそれが使えない場合、とりあえず
hogehogehoge(qaswdegthyuj .+ swedrfgtyhujik)?
このように絶対にヒットしないであろう文字列で挟んでその部分をオプション指定にすることで無効化できる。
意味としては・・・
hogehogehoge に続き、絶対マッチしないであろう文字列があってもいいしなくてもいい。つまりマッチしないので、なし、なくてもいいなので結論として「ない」ということになる。
・・・と思うんだが。これがダメなパターンはちょっと自分の頭では思いつかない