2012-02-02 80 views
0

我是新来的正则表达式,并争取找到匹配的话,其在括号{ }之间这是词和第一个字母是大写的,第二个是小写希望指针一切。所以我想忽略任何数字还包含数字之间找到{}

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

所以我只是想带回了比赛的话:

Test 
Tesgd 
Abc 

我已经看了使用\b\w对于那些话约束和[Az]为上依次降低,但不知道如何只得到这是支架之间只为好词。

+1

是否可以嵌套{}方括号?例如:{{aa,bb} cc},dd – 2012-02-03 00:01:59

+0

“第二个是小写字母”是否总是有第二个字母?第三个字母是大写还是小写? – 2012-02-03 00:02:50

+0

有可能有嵌套的括号,是的,对不起,我应该说,在第一个大写字母后面的所有其他字母应该是小写字母 – user1186144 2012-02-03 00:04:43

回答

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); 

我以为这是OK的,但里面没有最深层次paranthesis匹配。让我们分解一下正则表达式。 AAA意味着任意表达。 WWW是指任意的标识符(字母序列)

  • .是任意字符
  • [A-Z]是因为你可以猜测任何大写字母。
  • [^}]是任何字符,但}
  • ,|} | \ Z表示,}
  • *?字符串结束意味着赛前0或多次,但什么来懒洋洋地(做一个最小的匹配如果可能,吐出你吞下的东西尽可能多的匹配)
  • (?<=AAA)意味着AAA应该在左边匹配,然后才能真正尝试 来匹配某些东西。
  • (?=AAA)意味着AAA应与右侧 你真正匹配的东西之后。
  • (?<www>AAA)意味着匹配AAA,给你匹配的名字WWW的字符串。仅用于ExplicitCapture选项。
  • (?<depth>)匹配的一切,但也推“深度”在堆栈上。
  • (?<-depth>)匹配所有内容,但也弹出堆栈的“深度”。如果堆栈为空,则失败。

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

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

编辑:我纠正了正则表达式中的一个粗心的错误。 (在两个地方与[^}]*?取代.*?故事的士气:。这是很容易的正则表达式的引入错误

+0

这不起作用。在OP的示例字符串中,没有用大括号括起来的单词是'test5'和'test6',它们也不符合其他标准:它们不以大写字母开头,并且它们包含数字。用“Testx”替换其中一个,即使它没有用大括号括起来,也会看到它被标记为匹配。 – 2012-02-03 01:28:15

+0

糟糕。我纠正了它。它现在应该工作。谢谢。 – 2012-02-03 02:01:29

+0

+1。很好的详细解释。尽量不要在现实生活中如此:)。 – 2012-02-03 02:29:50

-1

不要在两个步骤的过滤。使用正则表达式

@"\{(.*)\}" 

拉出托架之间的片,和正则表达式

@"\b([A-Z][a-z]+)\b" 

拉出每个以大写字母开头,后面跟着小写的话字母。

+3

失败。第一个正则表达式贪婪,会匹配整个字符串。试试'@“\ {([^}] *)\}”' – 2012-02-02 23:53:10

0

在回答你原来的问题,我就提出了这样的正则表达式:

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

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

不幸的是,这是行不通的,因为(正如你在评论中提到的那样)大括号可能是嵌套的。匹配任何种类的嵌套或递归结构从根本上与正则表达式的工作方式不兼容。很多正则表达式都提供这种功能,但它们倾向于以不同的方式去实现,而且它总是很难看。下面是我会怎么做这在C#中,使用Balanced Groups

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”,并尝试匹配(?!)。没有任何东西是负面的,这是保证失败的;总是有可能无所适从。

嵌套与否,不需要使用逆序;向前看就足够了。大多数口味对后视都有严格限制,甚至没有人会认为尝试将它们用于这样的工作。 .NET没有这样的限制,所以你可能这样做的后顾之忧,但它没有多大意义。为什么所有这些工作在其他条件 - 大写首字母,无数字等等 - 测试时便宜得多?