1

ここで、誰もが考慮すべき興味深い問題があります。

文字で区切られた"/"文字列を解析してトークン化しようとしていますが、括弧の間にない場合のみです。

例えば:

根/枝1/枝2/葉

次のようにトークン化する必要があります: "Root""Branch1""Branch2""leaf"

ルート/ブランチ 1 (サブブランチ 1/サブブランチ 2)/リーフ

次のようにトークン化する必要があります: "Root""Branch1(subbranch1,subbranch2)""leaf"

ルート(branch1/branch2) テキスト(branch3/branch4) テキスト/ルート(branch1/branch2)/リーフ

"Root(branch1/branch2) text(branch3/branch4)""Root(branch1/branch2)"、としてトークン化する必要があります"leaf"

ONEを除くすべてのケースでうまく機能する次の式を思いつきました!

([^/()]*\((?<=\().*(?=\))\)[^/()]*)|([^/()]+)

これが機能しない唯一のケースは、次のテスト条件です。

ルート (ブランチ 1/ブランチ 2)/サブルート/サブルート (ブランチ 3/ブランチ 4)/リーフ

これは次のようにトークン化する必要"Root(branch1/branch2)"があります: , "SubRoot", "SubRoot(branch3/branch4)","Leaf"

代わりに得られる結果は、行全体に一致する 1 つのグループのみで構成されているため、まったくトークン化されていません。

「ルート(枝1/枝2)/サブルート/サブルート(枝3/枝4)/リーフ」

ここで起こっていることは、Regex が貪欲であるため、適切な区切り文字で停止することを知っているだけでなく、左端の開き括弧"("を最後の閉じ括弧と一致させていることです。")"

この追加のケースを処理するために、既存の式に小さな正規表現を追加する方法を理解するのに役立つ正規表現の達人はいますか?

ルート(branch1/branch2) テスト(branch3/branch4)/SubRoot/SubRoot(branch5/branch6)/Leaf

次のようにグループにトークン化する必要があります。

「ルート(branch1/branch2)テスト(branch3/branch4)」
「サブルート」
「サブルート(branch5/branch6)」
"葉"
4

3 に答える 3

1
List<string> Tokenize(strInput)
{
  var sb = new StringBuilder();
  var tokens = new List<string>();
  bool inParen = false;
  foreach(var c in strInput)
  {
      if (inParens)
      {
           if (c == ')')
               inParens = false;
           else
               sb.Append(c);
       }
       else if (c == '(')
               inParens = true;
       else if (c == '/')
            {
                 tokens.Add(sb.ToString());
                 sb.Length = 0;
            }
       else
             sb.Append(c);

  }
  if (sb.Length > 0)
      tokens.Add(sb.ToString());

  return tokens;
}

これはテストされていませんが、機能するはずです。(そしてほぼ確実に正規表現よりもはるかに高速になります)

于 2013-01-23T20:19:34.443 に答える
1

コストのかかるルックアラウンドアサーションを回避しようとする別のアプローチ...

/(\(.+?\)|[^\/(]+)+/

いくつかのコメントで...

/
(           # group things to be captured
  \(.+?\)   # 1 or more of anything in (escaped) brackets, un-greedily
|           # or ...
  [^\/(]+   # 1 or more, not slash, and not open bracket characters
)+          # repeat until done...
/
于 2013-01-23T20:24:31.867 に答える
0

以下は、バランスの取れたグループを使用して、一致する各アイテムをでキャプチャし、前のブラケットがバランスしていないときにRegex.Matchesクロージングが一致しないようにします。/

(?<=^|/)((?<br>\()|(?<-br>\))|[^()])*?(?(br)(?!))(?=$|/)

奇妙なことに、これは過度に設計されていますが (トークンごとに複数のネストされたブラケットのセットをサポートしている可能性があります)、Billy Moonはるかに単純な answerと同様に機能するようです。


以下は同様のことを行いますが、文字列を次のように分割Regex.Splitします(わかりやすくするために改行が追加されています)。

(?<=^(?(brb)(?!))(?:(?<-brb>\()|(?<brb>\))|[^()])*)
/
(?=(?:(?<bra>\()|(?<-bra>\))|[^()])*(?(bra)(?!))$)

これは、「文字列の先頭と文字列の間の括弧のバランスがとれている任意の場所、および文字列の末尾と文字列の間の括弧のバランスが取れている任意/の場所」に一致します。//

後読みでは、キャプチャが前と逆の順序で表示されることに注意してください。brbこれは、後読みが明らかに右から左に機能するためです。(これを教えてくれたコビに感謝します。)

これは、マッチ バージョンよりもはるかに遅いですが、とにかくそれを行う方法を考えたかったのです。

于 2013-01-23T20:25:49.357 に答える