キャプチャしない正規表現は()にする・・・って、え?
俺は正規表現が得意ではない。しかし、凡そどんなプログラミング言語でも役に立つ技術なので覚えておいて損はない。だから最近になって頑張って勉強をして、業務でも適切な機会があれば必ず正規表現を用いて書くようにしている。言うまでもなく慣れてくると非常に面白い。正規表現リテラルと称して/^hoge$/
と簡単に書けるRubyやJavaScriptの秀逸な設計を改めて認識してしまう。
話は変わってこんな記事がある。いい話(ウェブリオ辞めました) - アスペ日記
はてぶ数が非常に多く、退職エントリまとめでも最上位(ちなみに1位はこの人がGoogleを辞めたとき)。京大大学院卒で元Google社員という経歴から見れば、こんな浅学菲才の俺のような人間とは少し世界が異なるとは言わざるを得ない。プログラマーとしてのキャリアも翻訳ソフトで5年間、Googleで1年と俺のキャリアよりも全然長い。ただ、今日改めて読み直してみて話の核心部分に「んん?」と思うような部分があったので、少し感じたことを書いてみる。
まずは、引用。
ぼくは、キャプチャしない正規表現を (?:) でなくただの () で書くようレビューで高圧的に言われたとき、今の職場を辞めることを決意した。(まだ辞められていないのは純粋にぼくが無能なせいだ)
キャプチャしない正規表現を () で書くこと自体は、そこまでの悪じゃない。
ぼくも昔はそう書いていたし、(?:) を知ってからも使い続けていたし、今でもワンライナーならそう書くかもしれない。しかし、そう書くことを強制されるというのは、まったくの別問題だ。
それは人間としての尊厳に関わることだ。
「() で書いたほうがシンプルで読みやすい」と言われたら、確かに理がないわけではない。
でも、そのトレードオフで、そのいわゆる「読みやすさ」を重視することを選ぶ根拠、それを押し付けられる根拠は何だ? ということを突き詰めたら、相手のほうが「偉い」という「権力」しかない。
要は、
①「キャプチャしない正規表現は()
と書け」と言われた
②()
と書くことは間違ってないし自身は昔も今もそう書くことがある
③ただし強制されたのが気に食わない
という思考の流れなのであるが、これが理解できない。特に赤字の部分がおかしい。
つまり、このブログ主は「()
はキャプチャしない」ことは自分の経験から正しいと認めた上で、相手の主張は個人的には呑めないと言っている訳だ。恐らくキャリアからして正規表現には相当慣れ親しんでいる方と推測されるが、しかし今日の一般的な正規表現のルールから見ればこれは明らかに間違いだ。というのも()
でグループ化された部分は後から参照するかはともかく)キャプチャされる訳で、むしろそれを回避するために(?:)
が有るのだ。
しかし、問題はコメント欄でもそれを指摘する意見はひとつもない。はてなでも一件だけ「意味が分からない」というコメントがある以外はスルー。Twitterでもそれらしい指摘もない。ということは、違和感を持つ俺が少数派なんだと思う。
そもそも、ただのブログエントリーだ。それも愚痴混じりの。だから推敲せずに書いていたりもあるだろうし、ご本人の意図よりも更に大きく拡散されたという事情もあるだろう。純粋な日本人であっても肯定と否定を書き間違えて投稿してしまうことも普通にありえるし、大抵の人は「キャプチャしない正規表現でも()
と書けと言われた」という風に補完解釈したのだろう。しかし、それにしても誤解を招きやすい表現だ。言葉足らずにも程があるし、俺みたいに正規表現に弱い人間は暫く意味が分からず戸惑ってしまう。
最大限に推測を加えた結果、最終的な話の帰着点はこうなるのではないか。
後方参照しない(または名前つき後方参照のみを用いる)部分を(?:)
で明示的にキャプチャから外していたが、上司からは「読み易さのために()
でキャプチャしたままにしておけ」と言われた。
なお、正規表現の聖書とも言われることがあるオライリーの「詳説 正規表現」にこんな一説がある。
括弧の中の部分式にマッチしたテキストはキャプチャされ、$2に格納される。そして、ここではこの変数を使わない。グループ化には使えるが、使うつもりのない変数へのテキストの格納というオーバーヘッドのない(そして混乱を起こす危険性もない)括弧のタイプがあれば、もっとよくなるのではないのだろうか。
Perlなどの新しい正規表現は、そのための方法を提供している。グループ化してキャプチャする「(…)」ではなく、「(?:…)」という特殊な記法を使えば、グループ化はするがキャプチャはしない。
この方法によって得られるものは2つある。1つは、不要なキャプチャを避けることによってマッチ処理の効率が上がることだ。もう1つは、それぞれの目的のために必要なタイプの括弧を使えば、後でコードを読む人を混乱させずに、コードの意味をはっきり伝えられるということだ。目的にかかわらず同じ括弧が使われていたら、どういう意味で括弧が使われているのか迷うことになるだろう。
しかし、「(?:…)」という記法はちょっと不恰好だし、正規表現を一目で把握するということではかえってマイナスになっているのではないかとも考えられる。得られるメリットは。このコストに見合うものだろうか。私自身は、必要なタイプの括弧を正確に使うのを好む方だが、この例に限っては、わざわざ混乱を招く必要はないように感じる。たとえば、マッチは1回だけなので(ループで繰り返し行われているわけではないので)、効率が本当に問題になるようなケースではない。
この章では、キャプチャが不要な場合でも、見た目がすっきりしている「(…)」をつかっていくことにする。