2

私はif, else, endif独自の言語で古典的な実装をしています。

以下の文字列がある場合、ステートメントを見つけたいのですが、ブロック内にない[!--@Else--]ステートメントのみを探します。したがって、一致する前に s の偶数の開始と終了が必要です ...[!--@If--]...[!--@EndIf--]ifelse


ロレム・イプサム
[!--@If(1=1)--]
ひとつは
    [!--@If(2=1)--]
        2 は 1 ではありません
    [! - @そうしないと - ]
        だからこれをする
    [!--@EndIf--]
[! - @そうしないと - ]
1 は 1 ではありません
[!--@EndIf--]
そして何か他のもの

この例では、ブロックelse内にあるため、最初ではなく2 番目を見つけたいと考えています。if/endif

私は今、否定的および肯定的な後読みで数え切れないほどの時間を費やしており、それを機能させることができません!?

4

2 に答える 2

0

Abbondanza が述べたように、これを正規表現で行う場合は、グループのバランスを取る必要があります。警告する必要がありますが、これは良い解決策にはなりません。.NET の正規表現エンジンは、このようなケースを処理できる数少ないエンジンの 1 つですが、実際には推奨される方法ではありません。おそらく、言語を手動で解析したほうがよいでしょう。これにより、ネスト レベルをはるかに簡単に数えることができます。

とにかく、生産的なソフトウェアでこのタスクに正規表現が不適切である理由を示すために、ここに正規表現 (RegexOptions.IgnorePatternWhitespaceと を使用RegexOptions.Singleline) を示します。

(?<=\[!--@Else--\])      # Make sure that our match begins right after an else
                         # block.
[^\[]*                   # Match as many non-[ characters as possible (the actual
                         # statement)
(?=                      # This lookahead will assert that the previous statement
                         # was a top-level Else
  (?<Depth>)             # Push one capture onto the stack "Depth" (because, if
                         # this is one of the desired "Else"s we are exactly one
                         # level deep
  (?>                    # Start a subpattern for anything that could follow and
                         # suppress backtracking (because the alternatives are
                         # mutually exclusive)
    (?<Depth>\[!--@If\([^()]*\)--\])
                         # If we encounter an If block, push a new capture onto
                         # the stack (because the nesting level rises)
  |                      # OR
    (?<-Depth>)\[!--@EndIf--\]     
                         # IF we can pop a capture from the stack, consume an 
                         # EndIf. If we cannot, the named group will fail. Hence
                         # we can only consume one EndIf more than we already
                         # encountered Ifs.
  |                      # OR
    (?!\[!--@EndIf--\]). # If this character does not mark the beginning of an
                         # EndIf, consume an arbitrary character.
  )*                     # Repeat as long as possible.
  $                      # Make sure we have reached the end of the string.
  (?(Depth)(?!))         # If there is anything left on the stack, fail, too,
                         # because there are some Ifs that were not closed, so
                         # the syntax was invalid anyway.
                         # You can leave this out if you have convinced yourself
                         # beforehand that the overall nesting syntax is correct.
)                        # End of lookahead.

今、これはすでにかなりの獣であり、この小説のコメントなしではほとんど誰も理解できないでしょう.

しかし、仮定を単純化することに言及しました。どうぞ。

  1. If条件内に括弧を使用することはできません。それを行いたい場合は、それらの正しいネスティングも確認する必要があります。ここで行ったことよりも少し単純ですが、それでも括弧のスタックを上下に構築する必要があります。
  2. 主な問題はおそらく実際の試合[\[]]*です。開き括弧は一切使用できないため、Elseブロック内に条件ステートメントを含めることはできません。これを許可したい場合は、ほとんどすべてを実際の一致に再度コピーする必要があります。これにより、どのIfs とEndIfs が のにありElse、どの s がその後に来るかがわかります。

ご覧のとおり、すべてのケースを 100% カバーする正規表現ソリューションを取得するには、そのコードを完全に保守不可能にする必要があります。そのため、文字列を手動で分析し、ある種の構文ツリーを構築することを検討する必要があります。Elseこのようにして、見つけたい特定の s を簡単にトラバースできるネスト構造の OOP 表現を取得します。

于 2012-11-22T14:13:13.207 に答える
0

この正規表現を使用して、一致グループの一部として各 if ブロックの内容を取得できますVALUE。最も外側の一致は、配列内の最後の一致です。

(?<=\bif)(?>if(?<DEPTH>)|(?<VALUE-DEPTH>)endif|.?)*(?(DEPTH)(?!))(?=endif\b)

明確にするために、開始構文と終了構文を表すためにifandを使用していることに注意してください。endif

次に、グループの最後の値でこの正規表現を使用して、else 句を抽出できます。

(?<=else)((?!else).)+$
于 2012-11-22T13:36:14.347 に答える