Pythonで正規表現:先読みアサーション

拡張子を持ったファイル名の全てにマッチした正規表現は簡単で


.*[.].*$

となる。

次に拡張子batを持つファイル名以外のファイル名の全てにマッチした正規表現を見てみよう。


.*[.]bat$

と書くと目的に反対に拡張子batを持つファイル名のみにマッチする正規表現になる。


.*[.]([^b]..|.[^a].|..[^t])$

と書くと拡張子の部分は「先頭の文字bがない三文字か、真ん中に文字bがない3文字か、末尾に文字tがない三文字か」のマッチ要求になりよさそうだ。しかし拡張子は三文字とは限らない。

もっとすっきりと表現できる正規表現がある。それが先読みアサーションである。詳細は正規表現 HOWTOにある。


.*[.](?!bat$)[^.]*$

ここで(?!..)は否定先読みアサーションと呼ばれる記述で、今のばあいこの記述位置に文字列bat$があるとマッチは失敗となる(つまり最後尾がbatなっていると失敗)。ないと先に進む。[^.]*$は最後尾から文字.を含まない任意の長さの文字列という意味である。

正規表現 HOWTOには「このパターンで [^.]* を使うことで、ファイル名に複数のドットがあったときにも上手くいくようになります。」とあるが意味不明である。例えば、abc.cd.exeのようなファイル名を考える。このばあいabc.cd.までが.*[.]によってマッチングがされ、[^.]*$によってexeをマッチングする。

 
.*[.]      abc.cd.
[^.*]$      exe

従って複数のドットを処理しているのは.*[.]の部分のように思える。