1

这里有一个有趣的问题供大家考虑:

我正在尝试解析和标记由字符分隔的字符串,"/"但前提是不在括号之间。

例如:

根/分支1/分支2/叶

应标记为:"Root", "Branch1", "Branch2","leaf"

Root/Branch1(subbranch1/subbranch2)/叶子

应标记为:"Root", "Branch1(subbranch1,subbranch2)","leaf"

根(branch1/branch2)文本(branch3/branch4)文本/根(branch1/branch2)/叶

应标记为:"Root(branch1/branch2) text(branch3/branch4)", "Root(branch1/branch2)", "leaf".

我想出了以下表达式,它适用于除 ONE 之外的所有情况!

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

唯一不起作用的情况是以下测试条件:

根(branch1/branch2)/SubRoot/SubRoot(branch3/branch4)/叶子

应该被标记为:"Root(branch1/branch2)", "SubRoot", "SubRoot(branch3/branch4)","Leaf"

相反,我得到的结果只包含一个与整行匹配的组,因此它根本没有对其进行标记:

“根(分支 1/分支 2)/子根/子根(分支 3/分支 4)/叶”

这里发生的事情是,因为正则表达式是贪婪的,它会将最左边的左括号"("与最后一个右括号匹配,")"而不是仅仅知道在其适当的分隔符处停止。

你们那里的任何正则表达式专家都可以帮助我弄清楚如何在我现有的表达式中添加一个小的正则表达式片段来处理这个额外的情况?

Root(branch1/branch2) 测试(branch3/branch4)/SubRoot/SubRoot(branch5/branch6)/Leaf

应该被标记为组:

“根(分支 1/分支 2)测试(分支 3/分支 4)”
“子根”
“子根(分支 5/分支 6)”
“叶子”
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简单得多的答案类似,尽管这是过度设计的(每个令牌支持多个,可能嵌套的括号集)。


以下执行类似的操作,但使用(为清楚起见添加了换行符)拆分字符串Regex.Split

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

这匹配“/字符串开头和字符串之间的任何括号/是平衡的,并且/字符串结尾之间的任何括号是平衡的”。

请注意,在lookbehind 中,brb捕获以与之前相反的顺序出现 - 这是因为lookbehind 显然是从右到左工作的。(感谢Kobi的回答教会了我这一点。)

这比匹配版本慢得多,但我还是想弄清楚该怎么做。

于 2013-01-23T20:25:49.357 回答