【问题标题】:Why is this not a fixed width pattern?为什么这不是固定宽度的图案?
【发布时间】:2011-03-16 23:49:28
【问题描述】:

我正在尝试正确拆分英语句子,但我想出了下面的邪恶正则表达式:

(?<!\d|([A-Z]\.)|(\.[a-z]\.)|(\.\.\.)|etc\.|[Pp]rof\.|[Dd]r\.|[Mm]rs\.|[Mm]s\.|[Mm]z\.|[Mm]me\.)(?<=([\.!?])|(?<=([\.!?][\'\"])))[\s]+?(?=[\S])'

问题是,Python 不断出现以下错误:


Traceback (most recent call last):
  File "", line 1, in 
  File "sp.py", line 55, in analyze
    self.sentences = re.split(god_awful_regex, self.inputstr.strip())
  File "/System/Library/Frameworks/Python.framework/Versions/2.6/lib/python2.6/re.py", line 165, in split
    return _compile(pattern, 0).split(string, maxsplit)
  File "/System/Library/Frameworks/Python.framework/Versions/2.6/lib/python2.6/re.py", line 243, in _compile
    raise error, v # invalid expression
sre_constants.error: look-behind requires fixed-width pattern

为什么这不是一个有效的、固定宽度的正则表达式?我没有使用任何重复字符(* 或 +),只是 |。


编辑 @Anomie 解决了这个问题 - 非常感谢!不幸的是,我无法使新的表达平衡:

(?<!(\d))(?<![A-Z]\.)(?<!\.[a-z]\.)(?<!(\.\.\.))(?<!etc\.)(?<![Pp]rof\.)(?<![Dd]r\.)(?<![Mm]rs\.)(?<![Mm]s\.)(?<![Mm]z\.)(?<![Mm]me\.)(?:(?<=[\.!?])|(?<=[\.!?][\'\"\]))[\s]+?(?=[\S])

是我现在所拥有的。 ('s 的数量与 ('s 的数量相匹配:

>>> god_awful_regex = r'''(?<!(\d))(?<![A-Z]\.)(?<!\.[a-z]\.)(?<!(\.\.\.))(?<!etc\.)(?<![Pp]rof\.)(?<![Dd]r\.)(?<![Mm]rs\.)(?<![Mm]s\.)(?<![Mm]z\.)(?<![Mm]me\.)(?:(?<=[\.!?])|(?<=[\.!?][\'\"\]))[\s]+?(?=[\S])'''
>>> god_awful_regex.count('(')
17
>>> god_awful_regex.count(')')
17
>>> god_awful_regex.count('[')
13
>>> god_awful_regex.count(']')
13

还有什么想法吗?

【问题讨论】:

  • 我不知道,但可能是因为 [Pp]rof = 4 chars 而 [Mm]rs = 3 chars?
  • 关于不平衡括号:快速浏览一下,问题似乎是在您的正则表达式的末尾,您错误地转义了字符类的右括号,从而使右括号成为类而不是它们的实际功能。在其他情况下,您也已经超出必要的范围逃脱了。试试这个:r'''(?&lt;!(\d))(?&lt;![A-Z]\.)(?&lt;!\.[a-z]\.)(?&lt;!(\.\.\.))(?&lt;!etc\.)(?&lt;![Pp]rof\.)(?&lt;![Dd]r\.)(?&lt;![Mm]rs\.)(?&lt;![Mm]s\.)(?&lt;![Mm]z\.)(?&lt;![Mm]me\.)(?:(?&lt;=[.!?])|(?&lt;=[.!?]['"]))[\s]+?(?=[\S])'''
  • 另外,您可能希望通过使其不区分大小写来简化您的正则表达式(使用re.I 选项编译它)。

标签: python regex


【解决方案1】:

考虑这个子表达式:

(?<=([\.!?])|(?<=([\.!?][\'\"])))

| 的左侧是一个字符,而正确的大小为零。您在较大的负面回顾中也有同样的问题,可能是 1、2、3、4 或 5 个字符。

从逻辑上讲,(?&lt;!A|B|C) 的否定后视应该等价于一系列(?&lt;!A)(?&lt;!B)(?&lt;!C) 的后视。 (?&lt;=A|B|C) 的正向回溯应该等同于 (?:(?&lt;=A)|(?&lt;=B)|(?&lt;=C))

【讨论】:

    【解决方案2】:

    这并不能回答您的问题。但是,如果您想将文本拆分为句子,您可能需要查看nltk,其中包括PunktSentenceTokenizer 以及许多其他内容。这是一些标记器示例:

    """ PunktSentenceTokenizer
    
    A sentence tokenizer which uses an unsupervised algorithm to build a model
    for abbreviation words, collocations, and words that start sentences; and then
    uses that model to find sentence boundaries. This approach has been shown to
    work well for many European languages. """
    
    from nltk.tokenize.punkt import PunktSentenceTokenizer
    
    tokenizer = PunktSentenceTokenizer()
    print tokenizer.tokenize(__doc__)
    
    # [' PunktSentenceTokenizer\n\nA sentence tokenizer which uses an unsupervised
    # algorithm to build a model\nfor abbreviation words, collocations, and words
    # that start sentences; and then\nuses that model to find sentence boundaries.',
    # 'This approach has been shown to\nwork well for many European languages. ']
    

    【讨论】:

      【解决方案3】:

      看起来你可能在结尾处使用了重复的字符:

      [\s]+?
      

      除非我读错了。

      更新

      或者夜莺提到的竖条,这个问题的第一个答案似乎证实了:determine if regular expression only matches fixed-length strings

      【讨论】:

      • 是的,但是因为它是在后视之后它不应该影响它。
      • 正如 nightcracker 所说,“OR”垂直条允许匹配不同长度的字符串,也许这很重要?
      • 根据这个问题的第一个答案:stackoverflow.com/questions/3627570/… 竖线可能是罪魁祸首
      猜你喜欢
      • 2015-05-17
      • 2022-01-02
      • 2020-05-18
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2015-09-12
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多