Python正则表达式:XOR运算符

时间:2016-06-18 15:34:32

标签: python regex python-2.7

假设我有这样的字符串:

  1. "DT NN IN NN"
  2. "DT RB JJ NN"
  3. "DT JJ JJ NN"
  4. "DT RB RB NN NN"
  5. "DT RB RB"
  6. 所以,我有一个字符串列表:

    list = ["DT NN IN NN", "DT RB JJ NN", "DT JJ JJ NN", "DT RB RB NN NN", "DT RB RB"]
    

    我有以下代码:

    pattern = "(?:DT\s+)+([?:RB\s+|?:JJ\s+])+(?:NN\s+)*NN$"
    for item in list:
        m = re.match(pattern, item)
        if m:
            print item
    

    我想从pattern得到的是匹配以DT开头的字符串(出现一次或多次)RBJJ(出现一次或多次) ),但不是两者,然后以NN结束(再次出现一次或多次)。

    因此,在最终结果中,我应该在屏幕上打印3和4。但是,我的正则表达式,另外我得到2,我不想要。如何更改pattern以便这可行?如何用XOR更换管道(OR)?

3 个答案:

答案 0 :(得分:2)

问题在于如何定义RBJJ的存在。你没有提到只有它们中的任何一个应该存在。这可以通过用|(管道)分离它们并让它们中的任何一个重复一次或多次(+)来实现。尝试将模式更改为:

pattern = "(?:DT\s+)+(?:(RB\s+)+|(JJ\s+)+)(?:NN\s+)*NN$"

此外,(?:<something>)被称为非捕获组。你用它来说“我希望<something>匹配,但是当我稍后选择组时不包括它。而从它的外观来看,你没有使用任何组。你只是打印整个{{1} (除非你为了简洁而屏蔽了代码)。如果你实际上不需要组,这里有一个适合你的简单版本:

item

我还让白色空格的结束集合出现0次或更多次,而不是像原始模式那样出现一次或多次。随意改变它。

答案 1 :(得分:1)

[...]字符类,您要匹配包含?:+以及{{1}的一组字符等等。除了|标记系列之外,字符类中没有修饰符或特殊字符。

您需要匹配重复-RB

JJ

我把它简化了;你还没有使用任何一组。

此模式的在线演示:https://regex101.com/r/iH4lE6/1

由于您不依赖捕获组,因此使用非捕获组也没有任何意义;只需使用pattern = r"(?:DT\s+)+(?:(?:RB\s+)+|(?:JJ\s+)+)NN" 代替(...)即可获得更简洁的正则表达式。

您可能希望添加锚点以确保(?:...)仅在开始时匹配,并将最后的DT替换为NN以将其锚定在最后,并移动与每个重复组的开头匹配的空格:

(NN\s+)*NN$

此版本的在线演示:https://regex101.com/r/iH4lE6/2

答案 2 :(得分:1)

如果我正确理解了这个问题,你可以先把它分成两个不同的问题来解决这个问题:

  • RB开头,后跟一个或多个NN s后跟一个或多个^DT(\s+DT)*(\s+RB)+(\s+NN)+$ 的正则表达式:

    DT
  • JJ开头,后跟一个或多个NN s后跟一个或多个^DT(\s+DT)*(\s+JJ)+(\s+NN)+$ 的正则表达式:

    ^((DT(\s+DT)*(\s+RB)+(\s+NN)+)|(DT(\s+DT)*(\s+JJ)+(\s+NN)+))$
    

现在你可以简单地在这两者之间放一个管道(或操作员):

^DT(\s+DT)*((\s+RB)+|(\s+JJ)+)(\s+NN)+$

以后通过将其重构为:

来简化它
VectorDrawables

或使用Regexper的可视化表示:

visual representation of the regex