re.VERBOSE (正規表現を読みやすく)

複雑になりがちな正規表現を読みやすく、の話。

実は Python を使い始めるまで、こんなことが出来るとは知りもしなかった。言い訳としては、だな。emacs、sed、grep、awk といった、「正規表現を使える環境」というのはヤマほどあって、少しずつ違いがあって、必要最小限だけでこれらを行き来してきたから、だ。案外基礎的な「:alnum:」とかでさえ…違うでしょ?

で、python で出来るのはわかった。読みやすい。うん、使おうじゃないか。そこまではいいんだけれど、はて、これ、python だけだと困るなぁ、と思った。移植しなければならなくなったときのことを考えると、気が狂いそうだもの。

ruby は出来るね。「/x」だって。

1 # http://ruby-doc.org/ より
2 # A contrived pattern to match a number with optional decimal places
3 float_pat = /\A
4     [[:digit:]]+ # 1 or more digits before the decimal point
5     (\.          # Decimal point
6         [[:digit:]]+ # 1 or more digits after the decimal point
7     )? # The decimal point and following digits are optional
8 \Z/x
9 float_pat.match('3.14') #=> <MatchData "3.14" 1:".14">

perlも同じく /x。

PowerShellのは探すのちょっと苦労したけれど、要は .NET の「System.Text.RegularExpressions」なので、

を使える。ただし…、

この要領で、

 1 # hoge.ps1
 2 $str = "cookbook"
 3 $rx = @"
 4     [a-z]  # match lower alpha
 5     ook
 6 "@
 7 $matches = [regex]::matches($str, $rx, "IgnorePatternWhitespace")
 8 foreach ($m in $matches) {
 9     "$m"
10 }

実行

1 me@host: ~$ powershell -ExecutionPolicy RemoteSigned ./hoge.ps1
2 cook
3 book
4 me@host: ~$ 

あ、同じネタみっけ:

Javaのこれは:

 1 Pattern re = Pattern.compile(
 2   "^\\s*"+
 3   "(?:"+
 4     "(?:"+
 5       "([\\d]+)\\s*:\\s*"+  // Capture group #1
 6     ")?"+
 7     "(?:"+
 8       "([\\d]+)\\s*:\\s*"+  // Capture group #2
 9     ")"+
10   ")?"+ // First groups match 0 or 1 times
11   "([\\d]+)"+ // Capture group #3
12   "(?:\\s*[.,]\\s*([0-9]+))?"+ // Capture group #4 (0 or 1 times)
13   "\\s*$"
14 );

ネタだよなとは思うけれども、おっさる通り。同じ要領で C/C++ なら

 1 regexp_str =
 2   "^\\s*"
 3   "(?:"
 4     "(?:"
 5       "([\\d]+)\\s*:\\s*"  /* Capture group #1 */
 6     ")?"
 7     "(?:"
 8       "([\\d]+)\\s*:\\s*"  /* Capture group #2 */
 9     ")"
10   ")?" // First groups match 0 or 1 times
11   "([\\d]+)" /* Capture group #3 */
12   "(?:\\s*[.,]\\s*([0-9]+))?" /* Capture group #4 (0 or 1 times) */
13   "\\s*$";

みたいに出来るんだろうけれど、というか C/C++ は「正規表現の標準が未だ不十分」のよね。皆どれを使ってるのかね。boost がメジャー? GNU regexp とか Henry Spencer のとか…。Henry Spencer のは、更新されててビビった。それとも C++11 の regex を、皆喜んで使ってる? regex って TR1 にあったっけ? c++0x 時点で使えたっけ?

話戻そうっと。

アタシの場合馬鹿なんで、正規表現がちょっと複雑になったら、馬鹿に徹してすぐに分割しちゃうんで、正規表現内にコメントを書かなければならないほどのものは滅多に書かないです。デバッグもしにくくなるし。例えば正規表現で複雑な「|」(or)が続くくらいなら、別々の正規表現を書いて、プログラムの方が or で分岐するのを好みます。とはいえ…、やっぱりかなり簡単な部類の正規表現でも、すぐに読めなくなるよね、ってことで、「re.VERBOSE」は愛用しようと心に誓った。まる。