クイック スタート
チュートリアル
ツール & 言語
リファレンス
書籍 レビュー
正規表現チュートリアル
はじめに
目次
特殊文字
非印字文字
正規表現エンジンの内部
文字クラス
文字クラスの減算
文字クラスの積集合
ショートハンド文字クラス
ドット
アンカー
単語境界
選択
オプション項目
繰り返し
グループ化とキャプチャ
後方参照
後方参照、パート2
名前付きグループ
相対後方参照
ブランチリセットグループ
フリースペーシングとコメント
Unicode
モード修飾子
アトミックグループ化
所有格量指定子
先読みと後読み
先読みと後読み、パート2
マッチからテキストを除外する
条件
バランシンググループ
再帰
サブルーチン
無限再帰
再帰と量指定子
再帰とキャプチャ
再帰と後方参照
再帰とバックトラッキング
POSIXブラケット式
ゼロ長マッチ
継続マッチ
このサイトについて
はじめに
正規表現クイックスタート
正規表現チュートリアル
置換文字列チュートリアル
アプリケーションと言語
正規表現の例
正規表現リファレンス
置換文字列リファレンス
書籍レビュー
印刷可能なPDF
このサイトについて
RSSフィードとブログ
RegexBuddy—Better than a regular expression tutorial!

正規表現の再帰

Perl 5.10PCRE 4.0Ruby 2.0、およびこれら3つの後続のすべてのバージョンは、正規表現の再帰をサポートしています。Perlは構文(?R)(?0)の同義語として使用します。Ruby 2.0は\g<0>を使用します。PCREはバージョン7.7から3つすべてをサポートしています。以前のバージョンでは、Perlの構文のみをサポートしていました(Perlは実際にはPCREからコピーしました)。DelphiPHP、およびRの最近のバージョンも、正規表現関数がPCREに基づいているため、3つすべてをサポートしています。JGsoft V2も正規表現の再帰のすべてのバリエーションをサポートしています。

Ruby 1.9は正規表現の再帰の構文を持っていませんが、キャプチャグループの再帰をサポートしています。したがって、正規表現全体をキャプチャグループでラップすると、Ruby 1.9で正規表現全体を再帰させることができます。.NETは再帰をサポートしていませんが、バランシンググループをサポートしており、再帰の代わりにこれを使用してバランスの取れた構造をマッチさせることができます。

後で説明するように、Perl、PCRE、およびRubyが、再帰中の後方参照バックトラッキングをどのように処理するかには違いがあります。それらは互いの構文をコピーしましたが、互いの動作はコピーしませんでした。しかし、JGsoft V2はそれらの構文と動作をコピーしました。したがって、JGsoft V2には、異なる構文を使用することで選択できる、正規表現の再帰を行う3つの異なる方法があります。ただし、これらの違いは、このページの基本的な例では問題になりません。

Boost 1.42はPerlから構文をコピーしました。しかし、その実装はバグによって損なわれています。Boost 1.60は再帰における量指定子の動作を修正しようとしましたが、他のフレーバーとは大きく異なり、以前のバージョンのBoostとは互換性がありません。Boost 1.64では、無限再帰でクラッシュするのを最終的に停止しました。しかし、正規表現全体の再帰は、最初の選択肢のみを試みます。

単純な再帰

正規表現a(?R)?z, a(?0)?z、およびa\g<0>?zは、1つ以上の文字aの後に、まったく同じ数の文字zが続くものすべてにマッチします。これらの正規表現は機能的に同一であるため、この正規表現が文字列aaazzz.

にどのようにマッチするかを確認するために、再帰にRを使用する構文を使用します。aまず、aは文字列の最初の(?R)にマッチします。次に、正規表現エンジンはaに到達します。これにより、エンジンは文字列の現在の位置で正規表現全体をもう一度試みるように指示されます。さて、aは文字列の2番目の(?R)にマッチします。エンジンは再びaに到達します。2回目の再帰では、aは3番目のaにマッチします。3回目の再帰では、zは文字列の最初の(?R)にマッチしません。これにより、(?R) は失敗します。ただし、正規表現では量指定子を使用してzオプションにします。したがって、エンジンはzに進み、文字列の最初の

にマッチします。(?R)これで、正規表現エンジンは正規表現の終わりに到達しました。しかし、2レベルの再帰内にあるため、まだ全体的な一致は見つかっていません。見つかったのはzのみの一致です。一致が成功した後で再帰を終了すると、エンジンはzにも到達します。これで、文字列の2番目のzに到達します。2回目の再帰では、zにマッチします。エンジンはまだ再帰の1レベル深く、そこから一致が成功して終了します。最後に、aaazzzに到達します。エンジンは再び正規表現の終わりにあります。今回は再帰の中にはありません。したがって、全体的な正規表現の一致として

を返します。

バランスの取れた構造のマッチング再帰の主な目的は、バランスの取れた構造またはネストされた構造にマッチすることです。一般的な正規表現はb(?:m|(?R))*eです。ここで、bは構造の開始となるもので、mは構造の中央で発生する可能性のあるもので、eです。ここで、, は構造の開始となるもので、、およびは構造の中央で発生する可能性のあるもので、は構造の終わりに発生する可能性のあるものです。正しい結果を得るには、のいずれも同じテキストにマッチすることができないようにする必要があります。非キャプチャグループの代わりにアトミックグループを使用すると、パフォーマンスが向上します。.

b(?>m|(?R))*e一般的な実際の使用例は、バランスの取れた一連の括弧をマッチさせることです。\((?>[^()]|(?R))*\)

は、すべての括弧が適切にペアになっている限り、括弧で囲まれたテキスト(括弧の数に制限はありません)にマッチします。サブジェクト文字列にバランスの取れていない括弧が含まれている場合、最初の正規表現マッチは、バランスの取れていない開始括弧の後に発生する可能性のある、バランスの取れた括弧の左端のペアになります。バランスの取れていない括弧を含む文字列で一致を見つけない正規表現が必要な場合は、再帰の代わりにサブルーチンコールを使用する必要があります。バランスの取れた括弧の複数のペアのシーケンスを単一の一致として見つけたい場合は、サブルーチンコールも必要になります。

選択による再帰バランスの取れた構造の中央に表示されるものが、開始部分と終了部分なしで単独で表示される可能性もある場合、一般的な正規表現はb(?R)*e|mです。ここで、, は構造の開始となるもので、、およびは構造の中央で発生する可能性のあるもので、です。ここでも、はすべて相互に排他的である必要があります。\((?R)*\)|[^()]+

は、前のセクションの正規表現のように、バランスの取れた括弧のペアにマッチします。ただし、括弧をまったく含まないテキストにもマッチします。はすべて相互に排他的である必要があります。この正規表現は、Boostでは正しく機能しません。正規表現にグループ内にない選択がある場合、Boostでの正規表現全体の再帰は、最初の選択肢のみを試みます。したがって、は、間にテキストがない、任意に深くネストされたバランスの取れた括弧の数、または括弧をまったく含まないテキストにマッチします。選択肢を反転すると、[^()]+|\((?R)*\)

は、Boostでは、括弧を含まないテキスト、または括弧を含まないテキストで囲まれた括弧の単一のペアにマッチします。他のすべてのフレーバーでは、これらの2つの正規表現は同じマッチを見つけます。Boostの解決策は、選択をグループ内に入れることです。(?:\((?R)*\)|[^()]+)および(?:[^()]+|\((?R)*\))