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

文字列の同じ部分を複数の要件でテストする

先読みと後読みは、前のトピックで詳細に紹介された非常に強力な概念です。残念ながら、先読みと後読みは少し分かりにくいので、正規表現の初心者にはあまり使われていません。分かりにくいのは、先読みと後読みがゼロ幅であるということです。そのため、先読みに正規表現の別の部分が続く、または後読みに正規表現の別の部分が先行する正規表現がある場合、正規表現は文字列の一部を2回走査します。

より具体的な例でこれを明確にします。6文字の長さで、連続した3文字catを含む単語を見つけたいとしましょう。実際、先読みと後読みを使わずにこれと一致させることができます。すべてのオプションを指定し、選択を使用してそれらをまとめてグループ化しますcat\w{3}|\wcat\w{2}|\w{2}cat\w|\w{3}cat。簡単です。しかし、この方法は、「cat」、「dog」、または「mouse」を含む6文字から12文字の単語を見つけたい場合、扱いにくいものになります。

先読みと後読みによる解決

この例では、基本的に一致に2つの要件があります。まず、6文字の単語が必要です。次に、見つかった単語には「cat」という単語が含まれている必要があります。

6文字の単語との一致は\b\w{6}\bで簡単です。「cat」を含む単語との一致も同様に簡単です\b\w*cat\w*\b.

この2つを組み合わせると、次のようになります。(?=\b\w{6}\b)\b\w*cat\w*\b。簡単です!仕組みは次のとおりです。正規表現が試行される文字列の各文字位置で、エンジンは最初に肯定先読み内の正規表現を試行します。このサブレgex(したがって先読み)は、文字列内の現在の文字位置が文字列内の6文字の単語の先頭にある場合にのみ一致します。そうでない場合、先読みは失敗し、エンジンは文字列内の次の文字位置から最初から正規表現の試行を続けます。

先読みはゼロ幅です。そのため、先読み内の正規表現が6文字の単語を見つけると、文字列内の現在の位置はまだ6文字の単語の先頭にいます。正規表現エンジンはこの位置で正規表現の残りの部分を試行します。現在の位置で6文字の単語と一致させることができることが既にわかっているため、\bが一致し、最初の\w*が6回一致することがわかります。次に、エンジンはバックトラックし、\w*によって一致する文字数を減らして、catと一致するようにします。もしcatと一致しない場合、エンジンは文字列内の次の文字位置にある正規表現の先頭からやり直すしかありません。これは、先ほど見つけた6文字の単語の2番目の文字にあり、先読みは失敗し、エンジンが次の6文字の単語まで1文字ずつ進むことになります。

もしcatが正常に一致した場合、2番目の\w*は6文字の単語の残りの文字(もしあれば)を使用します。その後、正規表現の最後の\bは、先読み内の2番目の\bが一致した場所で確実に一致します。2つの要件を持つ正規表現が正常に一致しました。

ソリューションの最適化

上記の正規表現は正常に機能しますが、最適なソリューションではありません。テキストエディタで検索を実行するだけなら、これは問題ありません。しかし、この正規表現が繰り返し使用される場合、および/または開発中のアプリケーションで大規模なデータチャンクで使用される場合は、最適化することをお勧めします。

上記のように、正規表現を注意深く調べて正規表現エンジンがどのように適用するかを追跡すれば、これらの最適化を自分で発見できます。3番目と最後の\bは確実に一致します。単語境界はゼロ幅であるため、正規表現エンジンによって返される結果が変わることはないため、削除することができます。(?=\b\w{6}\b)\w*cat\w*。最後の\w*も確実に一致しますが、正規表現の一致に文字を追加するため、削除することはできません。先読みはその一致を破棄するため、正規表現エンジンによって返される一致には寄与しないことを忘れないでください。もし\w*を省略すると、結果の一致は「cat」を含む6文字の単語の先頭から「cat」までになり、単語全体にはなりません。

しかし、最初の\w*を最適化できます。現状では、6文字と一致してからバックトラックします。しかし、正常な一致では、「cat」の前に3文字以上存在することはできないことがわかっています。そのため、これを\w{0,3}に最適化できます。アスタリスクを遅延させても、これを十分に最適化できないことに注意してください。遅延アスタリスクはより早く正常な一致を見つけますが、6文字の単語に「cat」が含まれていない場合でも、正規表現エンジンは最後の2文字、最後の1文字、さらには6文字の単語の1文字先で「cat」との一致を試みます。

つまり、次のようになります。(?=\b\w{6}\b)\w{0,3}cat\w*。最後のマイナーな最適化には、最初の\bが含まれます。それ自体がゼロ幅であるため、先読みの中に置く必要はありません。そのため、最終的な正規表現は次のようになります。\b(?=\w{6}\b)\w{0,3}cat\w*.

最後の\w*\w{0,3}に置き換えることもできます。しかし、違いはありません。先読みは既に6文字の単語であることを確認しており、\w{0,3}catは既にその単語の3〜6文字と一致しています。正規表現を\w*または\w{0,3}のどちらで終わらせるかは問題ありません。どちらの方法でも、残りのすべての単語文字と一致します。結果の一致と見つかる速度が同じなので、入力しやすいバージョンを使用しても構いません。

より複雑な問題

それでは、「cat」、「dog」、または「mouse」を含む6文字から12文字の単語を見つけるには何を使用しますか?ここでも2つの要件があり、先読みを使用して簡単に組み合わせることができます\b(?=\w{6,12}\b)\w{0,9}(cat|dog|mouse)\w*。コツをつかめば非常に簡単です。この正規表現は、「cat」、「dog」、または「mouse」を最初の後方参照にも配置します。