PCRE と PCRE2

こんにちは。サイオステクノロジー OSS サポート担当 山本 です。

今回は正規表現を実装するために使用されるライブラリ PCRE についてのお話です。
PCRE は 2015年に新バージョン PCRE2 へと移行しており、元々の PCRE を使用していたソフトウェアでは近年のバージョンで PCRE から PCRE2 への移行を行なっているもの、行おうとしているものもあります。

此度はそのあたりを軸にざっくりとお話ししてみようと思います。

■正規表現と PCRE について

まず正規表現、そして PCRE についてざっくりとお話しておきます。

正規表現 (Regular Expression) は元々は学術的なものですが、
コンピュータの分野においては一定のルールを持つ記号を用いて書かれた主に検索などに用いられる文字列パターン、またはその文字列パターンを使って行うパターンマッチ・検索などを指します。
ルールの一例を挙げると、“.” は任意の 1文字を表していて、例えば “f.x” というパターンでは “fax”、”fix”、”fox” などにマッチさせることができる……などがあります。
“Regular Expression” のそれぞれの先頭部分を取って、”regex” や “regexp” などと表記される場合もあります。

この正規表現は異なる OS 間での互換性を保つための標準規格である POSIX にも含まれている他、プログラミング言語の機能として実装されていたり、いくつかのライブラリが作成されていたりと広く普及しています。
が、大元となる理論は同じなので基本的な機能は原則として同じです。一方、実装によってはより便利になるように独自の機能が追加されているケースもあり、「正規表現」と一纏めに覚えて同じものだと思っていると「別の環境で使えているはずのパターンが使えない?」と困惑する羽目になる可能性もあります。

今回話題にする PCRE (Perl Compatible Regular Expressions)1997年にリリースされた正規表現のライブラリの一種で、C言語で作成されています。
その名のとおり Perl (Perl5) で実装されていた形式の正規表現と互換性がある (=同じパターンが使える) 正規表現を実現するために作られたライブラリで、Apache や php、Nmap に postfix、postgres や zabbix など様々なソフトウェアでも使用されています

■PCRE と PCRE2

本記事を書いている時点では PCRE には 2つの大きなメジャーバージョンがあります。
現在は 2015年にリリースされた PCRE2 がメインのバージョンであり、最初のバージョンである PCRE は EoL となっています。

PCRE2 では全体的な改修に加え、Python や .NET、Oniguruma や JavaScript などの方式の正規表現と互換性を持たせるような構文の追加、自動的な最適化など様々な改善や性能向上が行われており、またそもそもいつかお話ししたとおり EoL を迎えたソフトウェアを使用し続けるのは望ましいことではないため、PCRE を使用しているなら可能であれば PCRE2 への移行を検討したほうがよいでしょう。

ところで先述のとおり PCRE は歴史が長く、様々なソフトウェアでも使用されているライブラリです。
(先に挙げたソフトウェアなどのように) それらのソフトウェアの中には当然 2015年以前から旧バージョンの PCRE を使用していたものもありますが、旧 PCRE が EoL となっているため、状況はまちまち (移行済み、両方使用可能、検討中など…) ではありますが PCRE2 への対応を進めているものもあります。
また、現在は旧 PCRE を使用しているソフトウェアでも (突然ということはないかと思いますが) 今後例えばメジャーバージョンの更新などに合わせて PCRE2 に完全に移行する、ということも恐らく出てくることでしょう。

一方で、PCRE2 では PCRE から使用方法が変更された点も当然存在しています。
例えば正規表現パターンにも機能追加などに伴うオプションなどの追加があり、極稀なケースではありますが PCRE で使えていた正規表現パターンが使えないこともあるようです。
また、API の関数名は一新されているため、PCRE の API 関数を直接使用している場合には PCRE2 移行時にその個所を全面的に見直す必要があります。

■PCRE2 でうまくいかないパターンの一例

PCRE では使えるのに PCRE2 では使えない正規表現パターンの一例として、以下のようなものがあります。

log[\s-_][0-9]{6}

この例で問題となるのは “[\s-_]” の部分で、PCRE2 だとこのパターンは構文エラーになります。

このパターンは「log 202402」「log-202402」「log_202402」などのように、

 ・”log” (log の部分)
 ・” (空白スペース:\s)” “-” “_” のうちいずれか1文字 ([\s-_] の部分)
 ・0 から 9 の間のいずれかの文字を6つ ([0-9]{6} の部分)

という文字列にマッチさせることを意図したものです。

“[]” はその中に含まれるいずれか1文字に合致すればマッチするというものなので一見問題なさそうですが、例のパターンの3つ目の部分 “[0-9]” で「0 から 9 までのいずれかの文字」を表現できるように、“[]” の中では “-” は範囲の指定に使用する記号でもあります。
PCRE2 では、”[\s-_]” というパターンは ” (空白スペース:\s)” から “_” の間のいずれかの文字と読み取られて、範囲の指定方法が不適切なため構文エラーとなってしまう……というカラクリになります。

このパターンは PCRE では使えるはずなので PCRE2 での変更点とも見れますが、どちらかというと PCRE で行なっていなかったチェックを適切に行うようになっただけという方が適当でしょう。

なお、PCRE2 では前にエスケープ記号を付けて “\-” としてやれば、範囲を示す記号ではなく “-” という文字として扱われるため、万が一 “[]” の中で “-” という文字を使いたい場合はエスケープ記号を忘れないようにしましょう。

log[\s\-_][0-9]{6}

この他にも様々な違いはあるかと思いますが、詳しく両者の違いを確認する場合は以下のマニュアルなどを確認してください。オプションの指定方法などが複数追加されているものの、既存のパターンへの影響は殆どなさそうなことがわかるかと思います。

 ・PCRE2 の構文マニュアル
 ・PCRE の構文マニュアル

ただし、このセクションでお話しした “[]” 内での “-” の扱いのように、機能の最適化・適正化などによりマニュアルからは読み取れない部分でユーザ側の意図とは異なる動作をするようになってしまうケースもないとは言えません
移行の際には十分なテストを忘れないようにしましょう。

■最後に

今回は PCRE と PCRE2 についてお話ししました。

今回は PCRE でお話ししましたが、PCRE に限らずソフトウェアは時代が進むにつれて機能追加や機器の高性能化に応じた改修、セキュリティ対策などなどのために更新されていくものです。
そして、更新の際に互換性がなくなってしまい、確認や改修が必要になることも時にはあります。

今回の PCRE のように他のソフトウェアからも使用されているものの更新では、使用しているソフトウェア側では「更新した」くらいの情報しか載っていない可能性も低くなく、油断すると見落としてしまうこともあるかもしれません。
更に、今回挙げた例のように「元々本来は想定していなかった動作を修正しただけ」という内容だと、マニュアル等の変更点から読み取れない部分で動作が変わって影響を受けてしまうといったケースもありえないとは言えません。

そういった際にトラブルの可能性を避けるためにも、更新前後のテストやバックアップなどは十全に行うようにしましょう。
そして繰り返しにはなりますが、だからと言って更新を行わないというのは基本的に望ましくない、ということは充分に留意してください。

ご覧いただきありがとうございます! この投稿はお役に立ちましたか?

役に立った 役に立たなかった

0人がこの投稿は役に立ったと言っています。

コメントを残す

メールアドレスが公開されることはありません。 が付いている欄は必須項目です