找到{}之间的所有内容

时间:2012-02-02 23:42:33

标签: c# regex

我是正则表达式的新手,并且希望指向找到{ }括号之间的单词匹配的指针,这些单词是单词,第一个字母是大写,第二个是小写。所以我想忽略任何数字也包含数字的单词

{ test1, Test2, Test, 1213, Tsg12, Tesgd} , test5, test6, {abc, Abc}

所以我只想把比赛带回来:

Test
Tesgd
Abc

我已经考虑过使用\b\w来判断绑定的单词,[Az]表示上层,然后是较低但不确定如何只获取括号之间的单词也是如此。

3 个答案:

答案 0 :(得分:3)

以下是您的解决方案:

Regex r = new Regex(@"(?<={[^}]*?({(?<depth>)[^}]*?}(?<-depth>))*?[^}]*?)(?<myword>[A-Z][a-z]+?)(?=,|}|\Z)", RegexOptions.ExplicitCapture);
string s = "{ test1, Test2, Test, 1213, Tsg12, Tesgd} , test5, test6, {abc, Abc}";
var m = r.Matches(s);
foreach (Match match in m)
   Console.WriteLine(match.Groups["myword"].Value);

我认为可以匹配内部而不是最深层的paranthesis。 让我们分析一下正则表达式。 AAA表示任意表达。 www表示任意标识符(字母序列)

  • .是任何字符
  • [A-Z]就像猜测任何大写字母一样。
  • [^}]}
  • 之内的任何字符
  • ,|} | \ Z表示,}或字符串结尾
  • *?表示匹配0次或更多次之前的内容但是懒惰(如果可能的话,请进行最小匹配并吐出您吞下的尽可能多的匹配项)
  • (?<=AAA)表示在您真正尝试之前,AAA应该在左侧匹配 匹配的东西。
  • (?=AAA)表示AAA应该在右侧匹配 在你真正匹配的东西之后。
  • (?<www>AAA)表示匹配AAA,并提供与名称www匹配的字符串。仅与ExplicitCapture选项一起使用。
  • (?<depth>)匹配所有内容,但也会在堆栈上推送“深度”。
  • (?<-depth>)匹配所有内容,但也会从堆栈中弹出“深度”。如果堆栈为空,则失败。

我们使用最后两项来确保我们在一个paranthesis内。如果没有嵌套的paranthesis或仅在最深的paranthesis中发生匹配,那将更加简单。

正则表达式适用于您的示例,可能没有错误。但是,我倾向于同意他人,你不应该盲目地复制你无法理解和维护的东西。正则表达很精彩,但前提是你愿意花时间去学习它们。

编辑:我在正则表达式中纠正了一个粗心的错误。 (在两个地方用.*?替换[^}]*?。故事的士气:在Regex中引入错误非常容易。

答案 1 :(得分:0)

在回答你原来的问题时,我会提供这个正则表达式:

\b[A-Z][a-z]+\b(?=[^{}]*})

最后一部分是积极的lookahead;它记录当前匹配位置,尝试匹配所包含的子表达式,然后将匹配位置返回到它开始的位置。在这种情况下,只要它们不是{},它就会在刚刚匹配的单词的末尾开始,并且可以吞噬尽可能多的字符。如果之后的下一个字符是},则表示该单词位于一对大括号内,因此前瞻成功。如果下一个字符是{,或者没有下一个字符,因为它位于字符串的末尾,则前瞻失败,正则表达式引擎继续尝试下一个字。

不幸的是,这不起作用,因为(正如你在评论中提到的)大括号可能是嵌套的。匹配任何类型的嵌套或递归结构从根本上与正则表达式的工作方式不兼容。许多正则表达式的口味无论如何都能提供这种能力,但它们倾向于以完全不同的方式进行,而且它总是很难看。以下是使用Balanced Groups在C#中执行此操作的方法:

  Regex r = new Regex(@"
      \b[A-Z][a-z]+\b
      (?!
        (?>
          [^{}]+
          |
          { (?<Open>)
          |
          } (?<-Open>)
        )*
        $
        (?(Open)(?!))
      )", RegexOptions.ExplicitCapture | RegexOptions.IgnorePatternWhitespace);
  string s = "testa Testb { Test1 Testc testd 1Test } Teste { Testf {testg Testh} testi } Testj";
  foreach (Match m in r.Matches(s))
  {
    Console.WriteLine(m.Value);
  }

输出:

Testc
Testf
Testh

我仍在使用前瞻,但这次我使用名为Open的组作为计数器,以跟踪相对于闭合括号数量的开括号的数量。如果当前正在考虑的单词未用括号括起来,那么当前瞻到达字符串末尾($)时,Open的值将为零。否则,无论是正面还是负面,conditional construct - (?(Open)(?!)) - 都会将其解释为“true”并尝试匹配(?!)。这是一个消极的前瞻,没有任何保证会失败;它总是可以匹配任何东西。

嵌套与否,没有必要使用lookbehind;前瞻就足够了。大多数口味严重限制了外观,没有人会想到尝试将它们用于这样的工作。 .NET没有这样的限制,所以你可以在后台做这件事,但这没有多大意义。为什么在其他条件 - 大写的第一个字母,没有数字等等 - 测试的成本要便宜得多时才能正常工作?

答案 2 :(得分:-1)

分两步进行过滤。使用正则表达式

@"\{(.*)\}"

拉出括号和正则表达式

之间的碎片
@"\b([A-Z][a-z]+)\b"

取出以大写字母开头的每个单词,然后是小写字母。