none
正規表現:グループ定義の均等化と正の後読みアサーションを組み合わせた動作について RRS feed

  • 質問

  • お世話になります。
    グループ定義の均等化(※1)とゼロ幅の正の後読みアサーション(※2)と以下のように組み合わせると思うように処理されません。

    var result1 = Regex.Matches("<abc><mno<xyz>>()", @"(?<=(((?'Open'<)[^<>]+)+((?'Close-Open'>)[^<>]*)+)+(?(Open)(?!)))\(\)");
    Debug.Assert(result1.Count == 1); // アサート失敗:実際はresult1.Count==0

    上記で、result1.Count==1とならないのは何が原因なのでしょうか。

    同様に、正の先読みアサーションと組み合わせると、予想通りの動作となります。

    var result2 = Regex.Matches("()<abc><mno<xyz>>", @"\(\)(?=(((?'Open'<)[^<>]+)+((?'Close-Open'>)[^<>]*)+)+(?(Open)(?!)))");
    Debug.Assert(result2.Count == 1); // OK

    よろしくお願いします。

    1
    http://msdn.microsoft.com/ja-jp/library/bs2twtah(v=vs.110).aspx#balancing_group_definition

    ※2
    http://msdn.microsoft.com/ja-jp/library/bs2twtah(v=vs.110).aspx#zerowidth_positive_lookbehind_assertion

    2014年12月1日 9:05

回答

  • 本件、マイクロソフトのサポートに問い合わせてご回答いただきました。

    ----ここから

    今回のサンプルでは、正規表現パターンを以下のように変更いただくことで、ご要望の検索結果を得られることを確認いたしました。
    グループ定義の均等化で利用しているグループの順序を入れ替えております。

      変更前 : @"(?<=(((?'Open'<)[^<>]+)+((?'Close-Open'>)[^<>]*)+)+(?(Open)(?!)))\(\)")
      変更後 : @"(?<=(((?'Close-Open'<)[^<>]+)+((?'Open'>)[^<>]*)+)+(?(Open)(?!)))\(\)")

    今回ご利用いただいております後読みアサーションでは、右から左へ向かって一致の評価が行われます。
    この際、グループ定義の均等化の部分に関しても、右から左に評価されることをご考慮いただく必要があり、今回ご要望の結果を得るためには、後読みアサーション部分のグループ名を入れ替えていただく必要があるものと考えられます。

    正規表現の後読みが右から左に向かって評価される点などの詳細につきましては、以下のドキュメントも合わせてご参照ください。

      正規表現の動作の詳細
      https://msdn.microsoft.com/ja-jp/library/vstudio/e347654k(v=vs.100).aspx
      ※ [正と負の後読み] の項をご参照ください。
      
    ----ここまで

    上記の通り、'Open'・'Close-Open'の順序が間違っていたことが原因でした。
    • 回答としてマーク murakami001 2015年1月22日 8:02
    2015年1月22日 8:02