正则表达式:匹配所有单词除了括号内的那些(C#)

时间:2016-10-03 15:54:18

标签: c# regex lookbehind

所以给出:

COLUMN_1, COLUMN_2, COLUMN_3, ((COLUMN_1) AS SOME TEXT) AS COLUMN_4, COLUMN_5

我将如何获得我的比赛:

COLUMN_1
COLUMN_2
COLUMN_3
COLUMN_4
COLUMN_5

我试过了:

(?<!(\(.*?\)))(\w+)(,\s*\w+)*?

但我觉得我已经离开了基地:(我正在使用regexstorm.net进行测试。

感谢任何帮助:)

4 个答案:

答案 0 :(得分:3)

你需要一个跟踪开括号和右括号的正则表达式,并确保只有一组平衡的括号(或根本没有括号)才匹配一个单词:

Regex regexObj = new Regex(
    @"\w+                  # Match a word
    (?=                    # only if it's possible to match the following:
        (?>                # Atomic group (used to avoid catastrophic backtracking):
           [^()]+          # Match any characters except parens
        |                  # or
           \(  (?<DEPTH>)  # a (, increasing the depth counter
        |                  # or
           \)  (?<-DEPTH>) # a ), decreasing the depth counter
        )*                 # any number of times.
        (?(DEPTH)(?!))     # Then make sure the depth counter is zero again
        $                  # at the end of the string.
    )                      # (End of lookahead assertion)", 
    RegexOptions.IgnorePatternWhitespace);

我尝试提供regexstorm.net的测试链接,但对于StackOverflow来说太长了。显然,SO也不喜欢URL缩短器,因此我无法直接链接,但您应该能够轻松地重新创建链接:http://bit[dot]ly/2cNZS0O

答案 1 :(得分:2)

匹配除了一些之外的所有单词是您可以使用正则表达式进行的最困难的练习之一。简单的方法是:只构造有限自动机,它接受你应该接受的字符串的原始非否定谓词,然后用不接受的字符串改变所有接受状态,最后构造一个等同于刚构造的自动机的正则表达式。这是一项很难完成的任务,因此处理它的最简单方法是为你想要否定的谓词构造正则表达式并将你的字符串传递给正则表达式匹配器,如果它匹配,只需拒绝它

这个问题的主要问题是计算机很容易做到,但是从自动机描述中构造正则表达式很繁琐,通常不会给你想要的结果(实际上是一个巨大的结果)。让我举一个例子来说明:

您已经要求匹配单词,但是从这些单词中,您想要那些不会出现在其中的单词。让我们假设我们想要与那组单词匹配的自动机,并假设我们匹配了该单词的第一个n-1个字母。这个字符串应该匹配,但前提是你没有得到下一个最后一个字母。所以正确的正则表达式应该是匹配第一个单词的所有字母而不是最后一个字母的正则表达式。不是,如果我们有一个匹配第一个单词但最后两个单词中所有字母的单词,我们可以跳过此测试,然后,回到第一个字母(很明显,如果你的正则表达式没有以单词的第一个字母开头,它无论如何都不匹配)让我们假设第一个单词是{{ 1}}。一个好的正则表达式匹配不等于BEGIN的东西是这样的:

BEGIN

另一种情况(使事情更复杂)是找到与字符串匹配的正则表达式,如果字符串中不包含单词[^B]|B[^E]|BE[^G]|BEG[^I]|BEGI[^N] 。让我们从相反的谓词中找到一个包含单词BEGIN的字符串

BEGIN

让我们构建其有限自动机:

^.*BEGIN.*$

其中双括号表示接受状态。如果你只是 将所有接受状态更改为不接受状态,您将获得一个自动机,接受第一个没有接受的所有字符串,反之亦然。

(0)---B--->(1)---E--->(2)---G--->(3)---I--->(4)---N--->((5))
 ^ \        |          |          |          |           ^ \
 | |        |          |          |          |           | |
 `-+<-------+<---------+<---------+<---------'           `-+

但将其转换为简单的正则表达式并非易事(如果你不相信我,你可以试试)

这只用一个词,所以想想如何匹配任何单词,构建自动机,然后切换每个州的接受 - 不接受状态。

在你的情况下,我们有一些事情需要处理,除了你的谓词与我制定的谓词不同的前提。我的谓词用于匹配其中包含一个单词的表达式(这是构建正则表达式的目标),但是如果用于匹配正则表达式中的组。如果您尝试我的示例,您会发现一个简单的字符串((0))--B-->((1))--E-->((2))--G-->((3))--I-->((4))--N-->(5) ^ \ | | | | ^ \ | | | | | | | | `-+<--------+<---------+<---------+<---------' `-+ (空字符串)与第二个正则表达式匹配,因为起始""状态是接受状态(好吧,空字符串不是&#39 ; t包含单词((0))),但您希望正则表达式匹配单词(而BEGIN不是单词)所以我们首先需要为您定义单词并构造常规单词与单词匹配的表达式:

""

应该是一个很好的候选人。它应该进入这样的自动机定义:

[a-zA-Z][a-zA-Z]*

并且你想要一个自动机同时接受(1 - 必须是一个单词,而不是单词集合中的2个)(不在单词集合中,不是第一个单词,而不是第二个而不是第三个...你可以通过首先构建一个匹配的自动机来构建它,如果它是第一个单词,第二个,第三个,...然后否定它)构造第一个自动机,第二个自动机,然后构造一个匹配两个的自动机。对于计算机而言,这也很容易用自动机完成,但不适合人们使用。

正如我所说,从正则表达式构造自动机对于计算机来说是一件简单而直接的事情,但对于一个人来说则不然。从自动机构造一个正则表达式也是,但是它会产生巨大的正则表达式,并且由于这个问题,大多数实现都会导致扩展符运算符的实现,如果某些正则表达式不相反则相反。

结论

使用否定运算符,允许您获取有关正则表达式接受器必须接受的字符串集的相反谓词,或者只是简单地构造一个正则表达式来执行简单的操作并使用布尔代数来完成其余的操作。

答案 2 :(得分:1)

这应该有效:

(?<!\()COLUMN_[\d](?!\))

试一试:https://regex101.com/r/bC4D7n/1

更新

好的,然后尝试使用这个正则表达式:

[\(]+[\w\s\W]+[\)]+

在这里演示:https://regex101.com/r/bC4D7n/2

答案 3 :(得分:1)

由于你有嵌套的括号,事情会变得棘手。虽然.NET RegEx引擎提供了使用堆栈内存的平衡组构造,但我采用了一种称为递归匹配的更通用的方法。

正则表达式:

\((?(?!\(|\)).|(?R))*\)|(\w+)

<强> Live demo

您需要的只是第一个捕获组。

交替左侧的说明:

\(           # Match an opening bracket
(?(?!\(|\))  # If next character is not `(` or `)`
    .             # Then match it
    |             # Otherwise
    (?R)          # Recurs whole pattern
)*           # As much as possible
\)           # Up to corresponding closing bracket