【问题标题】:Python regex: XOR operatorPython 正则表达式:XOR 运算符
【发布时间】:2016-10-20 07:14:31
【问题描述】:

假设我有这样的字符串:

  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"

所以,我有一个字符串列表:

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

【问题讨论】:

  • 所以NN 可以重复任意次数?
  • 在这种情况下,不使用正则表达式会简单得多。
  • 是的,NN 可以重复多次,但必须至少以一个NN 结尾。
  • @Belphegor:NN 可以与例如JJ 交错吗? DT JJ NN JJ NN 是一个有效的字符串吗?
  • @Belphegor:使用正则表达式进行自然语言模式处理? ;)

标签: python regex python-2.7


【解决方案1】:

[...] 是一个字符类,您正在匹配一组字符,其中包括?:+| 等。除了- 标记一个系列之外,字符类中没有修饰符或特殊字符。

您需要匹配RBJJ 的重复:

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

我已经把它简化了;无论如何,您都没有使用任何组。

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

由于您不依赖于捕获组,因此使用非捕获组也没有任何意义;只需使用 (...) 而不是 (?:...) 以获得更简洁的正则表达式。

您可能需要添加锚点以确保 DT 仅在开头匹配,并将末尾的 NN 替换为 (NN\s+)*NN$ 以将其锚定在末尾,并将空格匹配移动到开头每个重复组:

pattern = r"^DT(\s+DT)*((\s+RB)+|(\s+JJ)+)(\s+NN)+$"

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

【讨论】:

  • 基于this comment NN 可以重复任意次数。
  • 这对我不起作用,我在“DT JJ JJ NN JJ NN DT NN”之类的模式上得到了匹配,我不需要那个。它必须以 DT 开头,至少有一个(或多个)RB 或 JJ,然后以一个或多个 NN 结尾。
  • @Belphegor:更新;您能否更新您的问题以包含该示例?
  • @MartijnPieters 是的,现在可行(有一个例外:DT 可以出现多次,我更新了问题)。无论如何,另一个答案更快,所以我接受了那个。感谢您的帮助 +1!
  • @Belphegor:对,更新以匹配开头重复的 DT!
【解决方案2】:

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

  • DT 开头的正则表达式,后跟一个或多个RBs,后跟一个或多个NNs:

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

    ^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)+$

或者使用Regexper的视觉表示:

【讨论】:

  • 感谢您的评论,这有一个例外:DT 可以出现一次或多次(我刚刚看到我忘记在我原来的问题中提到这一点)。我接受了另一个答案,因为这在那里有效+另一个人更快:) +1 为您提供详细的答案,这绝对有帮助!
【解决方案3】:

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

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

另外,(?:<something>) 被称为非捕获组。您用它来表示“我希望匹配<something>,但在我稍后选择组时不包括在内。从外观上看,您没有使用任何组。您只是打印整个item(除非您'为了简洁起见,已经掩盖了代码)。如果您实际上不需要组,这里有一个适合您的简单版本:

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

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

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2012-10-30
    • 2013-11-18
    • 2013-10-26
    • 1970-01-01
    • 1970-01-01
    • 2023-03-10
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多