不是正则表达式

时间:2013-06-27 16:30:22

标签: regex

如何构建一个匹配所有具有ABC,DBE,ABE,FBG等序列的正则表达式,而不是XBZ?

我的示例序列ABC,DBE等仅仅是代表性的。我不是在寻找那些特定的模式。 A,B,C,D,E等可以采用任何模式的形式。例如,X,B和Z可以是单词。

具体来说,我希望找到所有包含B但不以X开头但后面没有Z的实例。

我使用反转匹配的grep -v选项提出了一种解决方法:

cat file | grep -ne ".*B.*" | grep -ve "XBZ"

但我宁愿有一个正则表达式。

7 个答案:

答案 0 :(得分:3)

到达那里需要一段时间,但这种模式:

(.*((?!X).B|B(?!Z).))|(^B)|(B$)

寻找(不是X的东西)B或B(不是Z的东西)。 TDD代码如下:

[Test]
public void TestPattern()
{
    const string pattern = "(.*((?!X).B|B(?!Z).))|(^B)|(B$)";

    Assert.IsFalse(Regex.IsMatch("Hello", pattern));
    Assert.IsTrue(Regex.IsMatch("Hello ABC", pattern));
    Assert.IsTrue(Regex.IsMatch("Hello DBE", pattern));
    Assert.IsTrue(Regex.IsMatch("Hello ABE", pattern));
    Assert.IsTrue(Regex.IsMatch("Hello FBG", pattern));
    Assert.IsTrue(Regex.IsMatch("Hello ABC World", pattern));
    Assert.IsTrue(Regex.IsMatch("Hello DBE World", pattern));
    Assert.IsTrue(Regex.IsMatch("Hello ABE World", pattern));
    Assert.IsTrue(Regex.IsMatch("Hello FBG World", pattern));
    Assert.IsTrue(Regex.IsMatch("ABC World", pattern));
    Assert.IsTrue(Regex.IsMatch("DBE World", pattern));
    Assert.IsTrue(Regex.IsMatch("ABE World", pattern));
    Assert.IsTrue(Regex.IsMatch("FBG World", pattern));
    Assert.IsTrue(Regex.IsMatch("Hello DBE World XBZ", pattern));
    Assert.IsTrue(Regex.IsMatch("Hello ABE World XBZ", pattern));
    Assert.IsTrue(Regex.IsMatch("Hello FBG World XBZ", pattern));
    Assert.IsFalse(Regex.IsMatch("Hello XBZ", pattern));
    Assert.IsTrue(Regex.IsMatch("Hello XB", pattern));
    Assert.IsTrue(Regex.IsMatch("Hello BZ", pattern));
    Assert.IsTrue(Regex.IsMatch("XB Hello", pattern));
    Assert.IsTrue(Regex.IsMatch("BZ Hello", pattern));
    Assert.IsTrue(Regex.IsMatch("B", pattern));
}

答案 1 :(得分:2)

当正则表达式在否定时关闭时,标准正则表达式中没有否定运算符。这纯粹是语法问题,没有什么可以阻止正则表达式引擎编写器在语法中添加非标准否定运算符...所以,它必须被重写为一组备选方案:

^([^X]..|X[^B].|XB[^Z])$

我不知道更好的方式......

P.S。在^内部有一个否定运算符[...],但它只匹配单个字符。它在上面使用。

答案 2 :(得分:2)

这是一种perl方式来完成这项工作:

my $re = qr/(?<!X)B(?!Z)/;
while(<DATA>) {
    chomp;
    say /$re/ ? "OK : $_" : "KO : $_";
}
__DATA__
ABC
DBE
ABE
FBG
XBZ

<强>输出:

OK : ABC
OK : DBE
OK : ABE
OK : FBG
KO : XBZ

<强>解释

(?-imsx:(?<!X)B(?!Z))

matches as follows:

NODE                     EXPLANATION
----------------------------------------------------------------------
(?-imsx:                 group, but do not capture (case-sensitive)
                         (with ^ and $ matching normally) (with . not
                         matching \n) (matching whitespace and #
                         normally):
----------------------------------------------------------------------
  (?<!                     look behind to see if there is not:
----------------------------------------------------------------------
    X                        'X'
----------------------------------------------------------------------
  )                        end of look-behind
----------------------------------------------------------------------
  B                        'B'
----------------------------------------------------------------------
  (?!                      look ahead to see if there is not:
----------------------------------------------------------------------
    Z                        'Z'
----------------------------------------------------------------------
  )                        end of look-ahead
----------------------------------------------------------------------
)                        end of grouping
----------------------------------------------------------------------

答案 3 :(得分:1)

您可以使用负面预测断言

来执行此操作
(?!^XBZ$)

答案 4 :(得分:1)

我根据评论中的假设写了一个编写正则表达式的函数。以下是假设:

  • 这是三个字符串
  • 字符一取自字母
  • 字符二总是一样的。在OP的帖子中,这是B。
  • 字符三是字符1 + 1.
  • 第一和第三个字符不能等于字符二。

    static void writeRegex(char skip)
    {
    string mydocpath = Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments);
    StringBuilder sb = new StringBuilder();
    sb.Append("^(");
    char one = 'A';
    char two = 'B';
    bool first = true;
    for (; one < 'Z' && two <= 'Z' ; )
    {
        if (!first)
        {
            sb.Append("|");   
        }
        first = false;
    
        if (one == skip)
        {
            one++;
        }
        if (two == skip || one == two)
        {
            two++;
        }
    
        sb.Append(one.ToString() + skip.ToString() + two.ToString());
    
        one++;
        two++;
    }
    sb.Append(")$");
    
    using (StreamWriter outfile = new StreamWriter(mydocpath + @"\Regex.txt"))
    {
        outfile.Write(sb.ToString());
    }
    

    }

当输入'B'时,产生:

  

^(ABC | CBD | DBE | EBF | FBG | GBH | HBI | IBJ | JBK | KBL | LBM | MBN | NBO | OBP | PBQ | QBR | RBS | SBT | TBU | UBV | VBW | WBX | XBY | YBZ)$

没有任何否定,只有三个角色的所有可接受结构的蛮力。

答案 5 :(得分:1)

W3C用于指定XMLXQuery的符号具有-运算符以进行排除,并且使其可用非常方便。例如,参见this rule(不区分大小写),不包括单词“XML”:

PITarget ::= Name - (('X' | 'x') ('M' | 'm') ('L' | 'l'))

基于DFA的正则表达式引擎可以通过利用正则表达式在差异下关闭这一事实来轻松支持这种排除。但是你并没有经常发现它的实现。

使用W3C表示法的一个解析器/词法分析器生成器REx。它将在某些时候开源,但我需要更多的时间来提供一些缺失的位,最值得注意的是文档。

使用这种表示法,您的示例可能如下所示:

Letter ::= [A-Z]
Three-Letter-Code ::= (Letter Letter Letter) - 'XBZ'

答案 6 :(得分:1)

我认为人们正在推翻这个问题。如果我正确地理解了这个问题 - 你希望正则表达式匹配一组特定的序列,而不是其他一些特定的序列 - 答案就是你不必告诉正则表达式不是匹配。它只匹配您指定的模式,而不是其他任何东西。 ABC|DBE|ABE|FBG匹配ABC或DBE或ABE或FBG,并且与任何其他序列(包括XBZ)不匹配。您不必专门指示它不匹配XBZ。