Jan Goyvaerts、Steven Levithan:正規表現クックブック

作成日 : 2021-04-15
最終更新日 :

概要

本書は正規表現の解説書である。目次などは下記にある。
https://www.oreilly.co.jp/books/9784873114507/

感想

この本はわたしにとって難しい。 個別には、JavaScript の正規表現パターンマッチングのページなどを作ったりして、 少しずつ覚えていったつもりだ。しかし、全く追いついていない。

入門

1 章は正規表現入門である。この本でカバーしているプラットフォームとバージョンは次のとおりである。なお、 プラットフォームということばは本書では使われていないが、言語ではないことを明示する意味で私の判断で用いた。

本書でカバーしている正規表現を扱うプラットフォームとバージョン
プラットフォームバージョン参考:2021 年 4 月現在の主なバージョン
Perl5.6, 5.8, 5.105.32
PCRE4, 5, 6, 710.36
.NET1.0 から 3.54.8
Java415
JavaScriptECMA-262 3ECMA-262 11
Python2.4, 2.53.9
Ruby1.8, 1.92.7, 3.0

ここで PCRE とは Perl-Compatible Regular Expression の略で、 オープンソースの C ライブラリである。本書によれば、実際には Perl 互換とはいいがたいようである。 さらに調べると、PCRE は 2015 年に後継の PCRE2 が発表され、こちらが 10.36 というバージョンである。 当初の PCRE は 8.44 である。この訳書が出版されて ちょうど 11 年があった。バージョンも大きく変わった。

これを調べるだけでも熱が出てしまったのだが、さらに追い打ちをかけるように pp.5-7 にかけて、 正規表現を使った置換において、置換テキストの特殊構文にはさまざまな方言があるというのだ。

本書でカバーしている置換テキストを扱うプラットフォームとバージョン
プラットフォームバージョン参考:2021 年 4 月現在の主なバージョン
Perl5.6, 5.8, 5.105.32
PHP(言及なし)8.0.3
.NET1.0 から 3.54.8
Java4, 5, 615
JavaScriptECMA-262 3ECMA-262 11
Python2.4, 2.53.9
Ruby1.8, 1.92.7, 3.0

ここで、置換テキストとは何か、p.106 を先取りして整理してみる。p.106 レシピ 2.21 は、 置換テキストへの正規表現をマッチの挿入を扱っている。以下、多少端折った形で引用する。

問題:URL を受け付け、その URL を指す HTML リンクを出力する置換処理を実行せよ。 ここで、URL とは http: で始まる、空白を含まない文字列と定義する。たとえば、 変換前の文章が Please visit http://www.regexcookbook.com とあれば、 変換後の文書は Please visit <a href="http://www.regrexcookbook.com">http://www.regexcoobook.com<a> となる。

正規表現は簡単だ。 http:\S+ でよい。これは、どのプラットフォームでも共通だ。 ところが、置換テキストの書き方はプラットフォームによってまちまちだ。

本書による置換テキスト
置換テキストプラットフォーム
<a href="$&">$&</a>.NET、JavaScript、Perl
<a href="$0">$0</a>.NET、Java、PHP
<a href="\0">\0</a>PHP、Ruby
<a href="\&">\&</a>Ruby
<a href="\g<0>">\g<0></a>Python

そういえば、マッチした文字列を参照するのは $1 だったか \1 だったかと考えていたことがあったのを思い出した。 これは正規表現ではないのか。なるほど。

なお、Ruby はバージョン 2.0 から鬼雲を採用している。

正規表現を操作するためのツール

紹介されているツールのうち、どれだけが残っているだろうか。興味があった。

リンクがない項目は、本書で指示された URL に実体がないものか、全く別のものが表示されているかしたところである。 リンクがある項目は、2021 年 4 月 17 日現在、サポートされていないと明示されていたものも含めて、 何らかの痕跡が残っているサイトである。これだけのものが残っているのは、大変なことだ。

基本スキル

2章は「正規表現の基本スキル」という表題だ。基本ではあるが、込み入ったところまで解説されている。 わたしがまず覚えておかなければいけないのは、メタ文字の12種類だ。

$()*+.?[\^{|

この本には書かれていないが、メタ文字に含まれていない記号は次の文字である。

!"#%&'-=~`@:;}]/<>,_

メタ文字に含まれない文字に } と ] があるのが意外だった。 それから、<>/&" もメタ文字ではないことを改めて認識したのだった。 以下長くなるが引用する。

メタ文字のリストに含まれていないもので目立つのは、 閉じ角かっこ( ] )、ハイフン( - )、閉じ中かっこ( } )です。 最初の2つがメタ文字になるのは、エスケープされていない [ の後だけであり、 } がメタ文字になるのはエスケープされていない { の後だけです。 } をエスケープする必要はありません。[ と ] の間のブロックにおけるメタ文字の規則については、 レシピ 2.3 で説明します。

この段落を読んでいると、開きかっこと閉じかっこは記号に対しての説明であるにもかかわらず、 記号としてのかっこを見て、開きと閉じの対応を勝手に読み取ってしまい、 脳が混乱した一種のトランス状態になる。ちょうど、 井上ひさしの「括弧の恋」を思い出すのだった。

何を言っているのかわからない人がいるかもしれないが、「モーニング娘。」や「藤岡弘、」、「本田美奈子.」 が出てくる文面で混乱するのと同じことだ。

不要なバックトラックの削減

p.88 から始まる「 レシピ2.15 不要なバックトラックの削減」について、 量指定子についての理解が難しい。 まず、欲張りな量指定子と、控えめな量指定子の区別はわかる。 欲張りな量指定子はおそらく greedy quantifier だろう。 では、どん欲な量指定子とはなんだろう。possesive quantifier だろうか。 他のサイトを見ると、「強欲な量指定子」としているところもあるらしい。

すぐにはわからないが、不要なバックトラックの削減には、 絶対最大量指定子を使う(記法が最も簡単)か、 アトミックグループを使う(記法は多少複雑だが一般性あり)らしい。

p.88 では、JavaScript と Python は、絶対最大量指定子もアトミックグループもサポートしていません。 と書かれている。現在の Python では、標準モジュールの re ではサポートされていないので、 regex モジュールを使うということである。regex モジュールをインストールしてみよう。

$ conda install regex

インストールはできた。あとは使った結果だが、宿題とする。

プログラムの中の正規表現

正規表現はプログラムで使うものだから、 わざわざ3章 で「プログラムの中の正規表現」という表題をつけるのは少し不思議な感じがした。 しかし本書を読んで、正規表現の使い方と合わせて、特定のプログラミング言語での正規表現の使い方を知ることは必要だ、 と感じたのだった。たとえば、同じ .NET を使っていても、プログラミング言語が違えば使い方も異なる。 具体的には、C# と VB.NET では違うということだ。また、ライブラリとして流通している PCRE もあり、 これを採用している PHP では PCRE を使うための書き方が必要である。

データチェックと整形

4章 の「データチェックと整形」は幅広いチェックの対象と方法について述べられている。 最初は電子メールのアドレスのチェックで始まるが、ここでは、 このレシピは、正規表現を書き始める前に、 何にマッチさせたいかを正確に決めておかなければならないということを示す好例になっています。 と指摘している。確かにそうだ。

p.284 以降は、テキストの行数を制限するということで、文字列に含まれる文字数とは無関係に、 文字列が5行以下かどうかをチェックするレシピを解説している。 このレシピでは、行の区切り(終端)のために使われている文字や文字シーエンスは、 いろいろな事情により異なることが示されている。 そして、解答では次の3種類の改行をサポートするということである。

いうまでもないが、古い MacOS に対して、新しい MacOS は OS X である。 私は古い MacOS しか使ったことがない。今調べてわかったのだが、 OS X とは旧称であり、 現在の Macinsoth の OS 、ここでいう Mac OS 10.0以降の OS は単に MacOS と呼ぶこと、 Mac OS X 10.0 より前の OS は Classic Mac OS と呼ぶことを知った。

本書では、原書での誤りとされる表現を訳者が直している。すべてを掲載するのははばかられるので、 ここでは JavaScript 方言だけを示す。

^(?:[^\r\n]*(?:\r\n?)){0,4}[^\r\n]*(?:\r\n?|\n)?$

単語

単語の境界に一致する正規表現は \b である。5章の「単語、行、特殊文字」では、 この表現が駆使されている。しかし、日本語は空白で単語を区切る表記法ではないので、 あまり役に立たないのが悲しい。

p.354 で、文字列の先頭と末尾の空白を取り除く正規表現が出ている。 ここでは、JavaScript では組み込み関数/メソッドがないように書かれているが、 現在は trim() メソッドがある。
https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Global_Objects/String/trim

数値

6章は数値について充てられている。実際には適用用途について考えるべきだろう。 たとえば、レシピ 6.1 の整数では、 「大きなテキストからさまざまな種類の 10 進整数を見つける正規表現を作ってください。」 という問題だ。「さまざまな」というのが曲者であるので、解答はいろいろある。 大きなテキストに含まれる 10 進正整数を探すのであれば、 \b[0-9]+\b となっている。 ここで、いかし、先頭に 0 がつく数字の並びは数ではない、 という見方もあるだろうから \b[1-9]+[0-9]*\b という回答もあるだろう。 また、言語によっては、0が先頭につく0から7までの数字のならびを8進数と解釈するものもある。

p.365 では、私たちは略記法の ‹\d› よりも ‹[0-9]› のように明示的に範囲を使う方がよいと思っています。 といっている。私もそう思う。

URL、パス、インターネットアドレス

表題のこれらは、正規表現で対応する甲斐があるというべきだろう。URL から、 (スキーム|ユーザー|ホスト|ポート|パス|クエリー|フラグメント)を抽出するのは、 私はもっと早くに知っておけばよかったと思うのだった。

マークアップとデータのやりとり

8章は「マークアップとデータのやりとり」である。この章だけではないが、 長い正規表現にはかならずフリーフォーマットモードの解答があり、 フリーフォーマットモードのない JavaScript が不遇をかこっているという気になった。

誤植

上記 O'reilly のページには誤植情報がないが、私が見た限りいくつかあったので、 ここで確認しておきたい。

p.33 の「大文字と小文字の区別なし」の書き方を2例挙げているが、この2例は全く同じものである。

p.121 の JavaScript の項の最後の行、 「エスケープしなければなりますが、」とあるが、 「エスケープしなければなりませんが、」のまちがいだろう。

正規表現についてのリンク

書誌情報

書名正規表現クックブック
著者Jan Goyvaerts、Steven Levithan
訳者長尾 高弘
発行日2010 年 4 月 16 日(初版第1刷)
発行元オライリー・ジャパン
定価円(本体)
サイズ
ISBN 978-4-87311-450-7
その他越谷市立図書館で借りて読む

まりんきょ学問所コンピュータの部屋Unix, Linux > Jan Goyvaerts、Steven Levithan:正規表現クックブック


MARUYAMA Satosi