10

最初に、この質問は、グループを取得する方法や、私がよく知っている正規表現の 2 つの機能である量指定子の使用方法に関するものではないことを説明させてください。エキゾチックなエンジンの珍しい構文に精通している可能性のある正規表現愛好家にとっては、より高度な質問です。

数量詞のキャプチャ

正規表現フレーバーで量指定子をキャプチャできるかどうか知っている人はいますか? これにより、+ や * などの量指定子によって一致する文字の数がカウントされ、この数が別の量指定子で再び使用できるようになるということです。

たとえば、次のような文字列で L と R の数が同じであることを確認したいとします: LLLRRRRR

次のような構文を想像できます

L(+)R{\q1}

ここで、L の + 量指定子がキャプチャされ、キャプチャされた数値が R の量指定子で {\q1} として参照されます。

@@@@ "Star Wars" ==== "1977" ---- "Science Fiction" //// "ジョージ・ルーカス」

再帰との関係

場合によっては、量指定子のキャプチャが再帰をエレガントに置き換えます。たとえば、同じ数の L と R で囲まれたテキストの一部、

L(+) some_content R{\q1} 

このアイデアは、次のページで詳細に説明されています:キャプチャされた量指定子

また、キャプチャされた量指定子の自然な拡張についても説明します。前に一致した文字数 (3*x + 1) に一致させたい場合の量指定子算術です。

このようなものが存在するかどうかを調べようとしています。

あなたの洞察を事前にありがとう!!!

アップデート

Casimir は、パターンのさまざまな部分が同じ長さであることを検証する 2 つの方法を示す素晴らしい回答を出しました。しかし、日常業務ではどちらにも頼りたくありません。これらは本当に素晴らしいショーマンシップを示すトリックです。私の考えでは、これらの美しいが複雑な方法は、質問の前提を確認します: 数量詞 (+ や * など) が一致できる文字数を取得する正規表現機能は、そのようなバランスパターンを非常に単純にし、構文を拡張します心地よい表現方法。

更新 2 (かなり後で)

.NET には、私が求めていたものに近い機能があることがわかりました。機能を実証するための回答を追加しました。

4

2 に答える 2

13

量指定子を取得できる正規表現エンジンを知りません。ただし、PCRE または Perl を使用すると、いくつかのトリックを使用して、同じ数の文字があるかどうかを確認することができます。あなたの例では:

@@@@ "スターウォーズ" ==== "1977" ---- "サイエンスフィクション" //// "ジョージ・ルーカス"

有名な Qtax トリック@ = - /を使用するこのパターンでバランスが取れているかどうかを確認できます (準備はできていますか?): 「所有オプションの自己参照グループ」

~(?<!@)((?:@(?=[^=]*(\2?+=)[^-]*(\3?+-)[^/]*(\4?+/)))+)(?!@)(?=[^=]*\2(?!=)[^-]*\3(?!-)[^/]*\4(?!/))~

パターンの詳細:

~                          # pattern delimiter
(?<!@)                     # negative lookbehind used as an @ boundary
(                          # first capturing group for the @
    (?:
        @                  # one @
        (?=                # checks that each @ is followed by the same number
                           # of = - /  
            [^=]*          # all that is not an =
            (\2?+=)        # The possessive optional self-referencing group:
                           # capture group 2: backreference to itself + one = 
            [^-]*(\3?+-)   # the same for -
            [^/]*(\4?+/)   # the same for /
        )                  # close the lookahead
    )+                     # close the non-capturing group and repeat
)                          # close the first capturing group
(?!@)                      # negative lookahead used as an @ boundary too.

# this checks the boundaries for all groups
(?=[^=]*\2(?!=)[^-]*\3(?!-)[^/]*\4(?!/))
~

本旨

非キャプチャ グループには 1 つだけが含まれます@。このグループが繰り返されるたびに、キャプチャ グループ 2、3、および 4 に新しいキャラクターが追加されます。

所有格オプションの自己参照グループ

それはどのように機能しますか?

( (?: @ (?= [^=]* (\2?+ = ) .....) )+ )

@ 文字が最初に出現した時点では、キャプチャ グループ 2 はまだ定義されていない(\2 =)ため、パターンが失敗するようなものを記述することはできません。この問題を回避するには、後方参照をオプションにする方法があります。\2?

このグループの 2 番目の側面は、=一致する文字の数が非キャプチャ グループの繰り返しごとに増加することです。これは、=毎回追加されるためです。この数が常に増加する (またはパターンが失敗する) ことを保証するために、所有量指定子は、新しい=文字を追加する前に、まず後方参照を強制的に一致させます。

このグループは次のように表示されることに注意してください。グループ 2 が存在する場合は、次のグループと一致します。=

( (?(2)\2) = )

再帰的な方法

~(?<!@)(?=(@(?>[^@=]+|(?-1))*=)(?!=))(?=(@(?>[^@-]+|(?-1))*-)(?!-))(?=(@(?>[^@/]+|(?-1))*/)(?!/))~

@ 部分を数回使用するため、オーバーラップ マッチを使用する必要があります。これが、すべてのパターンがルックアラウンド内にある理由です。

パターンの詳細:

(?<!@)                # left @ boundary
(?=                   # open a lookahead (to allow overlapped matches)
    (                 # open a capturing group
        @
        (?>           # open an atomic group
            [^@=]+    # all that is not an @ or an =, one or more times
          |           # OR
            (?-1)     # recursion: the last defined capturing group (the current here)
        )*            # repeat zero or more the atomic group
        =             #
    )                 # close the capture group
    (?!=)             # checks the = boundary
)                     # close the lookahead
(?=(@(?>[^@-]+|(?-1))*-)(?!-))  # the same for -
(?=(@(?>[^@/]+|(?-1))*/)(?!/))  # the same for /

= -前のパターンとの主な違いは、これがと/グループの順序を気にしないことです。(ただし、文字クラスと否定先読みを使用して、最初のパターンに簡単に変更を加えて、それに対処することができます。)

注: 文字列の例では、より具体的には、否定後読みをアンカー (^または\A) に置き換えることができます。そして、文字列全体をマッチ結果として取得したい場合は.*、最後に追加する必要があります (そうしないと、マッチ結果はふざけて気づいたように空になります)。

于 2014-04-11T01:37:36.930 に答える