我正在使用一个(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断言可以使本例正常工作,但会破坏其他一些测试。我该怎么解决这个问题呢?在
在尝试了一下
_sre.so
在这种情况下正在做什么(太复杂了!)但我尝试过的一个“盲修复”似乎可以转换为互补字符集的否定前瞻断言…:例如,我把原来的
(?=[\d:., ]))
正展望改为“双否定”形式(补码的负前瞻)(?![^\d:., ]))
,这似乎消除了扰动。这个对你合适吗?在我认为这是
_sre.so
这种情况下的一种实现异常,看看其他RE引擎在这两种情况下会做些什么,就像进行健全性检查一样。在“未来展望”并不是真的对任何事情都短路。regex只是在某种程度上贪婪。它更喜欢在第一个大块中匹配,因为它不想跨越“|”边界到regex的第二部分,并且必须检查它。在
由于整个字符串与第一个大块不匹配(因为lookeahead说它后面需要跟一个特定的字符,而不是行尾),它只匹配“thessalonian”组中的“Th”,lookahead在“Th Jn”中看到“Th”后面有一个空格,所以它认为这是一个有效的匹配。在
你可能想做的是移动“|帖撒罗尼迦前书|约翰| Th | Jn)\?”组队去另一个大的“|”街区。在课文的开头或结尾检查你的两个单词书,或者在第三组中检查一个单词的书。在
希望这个解释有道理。在
我在提问时发现了另一种解决方案:切换块的顺序,首先进行行尾检查,然后最后是lookahead断言。但是,我更喜欢Alex的双负解,并且已经实现了它。在
相关问题 更多 >
编程相关推荐