前瞻性断言似乎缩短了正则表达式中替换项的排序

2024-09-27 09:32:11 发布

您现在位置:Python中文网/ 问答频道 /正文

我正在使用一个(Python风格的)正则表达式来识别圣经引用的常见和特殊形式以及缩写。给出以下详细代码段:

>>> cp = re.compile(ur"""
    (?:(
        # Numbered books
        (?:(?:Third|Thir|Thi|III|3rd|Th|3)\ ? 
           (?:John|Joh|Jhn|Jo|Jn|Jn|J))
        # Other books
        |Thessalonians|John|Th|Jn)\ ? 
      # Lookahead for numbers or punctuation
      (?=[\d:., ]))

    |

    # Do the same check, this time at the end of the string.
    (
      (?:(?:Third|Thir|Thi|III|3rd|Th|3)\ ?
         (?:John|Joh|Jhn|Jo|Jn|Jn|J))
      |Thessalonians|John|Th|Jn)\.?$
    """, re.IGNORECASE | re.VERBOSE)

>>> cp.match("Third John").group()
'Third John'

>>> cp.match("Th Jn").group()
'Th'

>>> cp.match("Th Jn ").group()
'Th Jn'

这个片段的目的是匹配各种形式的“第三约翰”,以及形式的“帖撒罗尼迦”和“约翰”。在大多数情况下,这是好的,但它不匹配“Th Jn”(或“Th John”),而是与“Th”本身匹配。在

我已经明确地将表达式中每个缩写的出现顺序从最长到最短,以避免出现这样的情况,这依赖于正则表达式典型的贪婪行为。但积极的前瞻性断言似乎是在缩短这一顺序,选择最短的匹配而不是最贪婪的匹配。在

当然,删除lookahead断言可以使本例正常工作,但会破坏其他一些测试。我该怎么解决这个问题呢?在


Tags: therematchgroupjohnbookscp形式
3条回答

在尝试了一下_sre.so在这种情况下正在做什么(太复杂了!)但我尝试过的一个“盲修复”似乎可以转换为互补字符集的否定前瞻断言…:

cp = re.compile(ur"""
(?:(
    # Numbered books
    (?:(?:Third|Thir|Thi|III|3rd|Th|3)\ ? 
       (?:John|Joh|Jhn|Jo|Jn|Jn|J))
    # Other books
    |Thessalonians|John|Th|Jn)\ ? 
  # Lookahead for numbers or punctuation
  (?![^\d:., ]))

|

例如,我把原来的(?=[\d:., ]))正展望改为“双否定”形式(补码的负前瞻)(?![^\d:., ])),这似乎消除了扰动。这个对你合适吗?在

我认为这是_sre.so这种情况下的一种实现异常,看看其他RE引擎在这两种情况下会做些什么,就像进行健全性检查一样。在

“未来展望”并不是真的对任何事情都短路。regex只是在某种程度上贪婪。它更喜欢在第一个大块中匹配,因为它不想跨越“|”边界到regex的第二部分,并且必须检查它。在

由于整个字符串与第一个大块不匹配(因为lookeahead说它后面需要跟一个特定的字符,而不是行尾),它只匹配“thessalonian”组中的“Th”,lookahead在“Th Jn”中看到“Th”后面有一个空格,所以它认为这是一个有效的匹配。在

你可能想做的是移动“|帖撒罗尼迦前书|约翰| Th | Jn)\?”组队去另一个大的“|”街区。在课文的开头或结尾检查你的两个单词书,或者在第三组中检查一个单词的书。在

希望这个解释有道理。在

我在提问时发现了另一种解决方案:切换块的顺序,首先进行行尾检查,然后最后是lookahead断言。但是,我更喜欢Alex的双负解,并且已经实现了它。在

相关问题 更多 >

    热门问题