使用PyPi regex包无法将数字范围与DEFINE块中声明的模式相匹配



我正在使用https://github.com/mrabarnett/mrab-regex(通过pip install regex,但此处出现故障:

pattern_string =  r'''
(?&N)
^ W*? ENTRY              W* (?P<entries>    (?&Range)    )     (?&N)
(?(DEFINE)
(?P<Decimal>
[ ]*? d+ (?:[.,] d+)? [ ]*?
)
(?P<Range>
(?&Decimal) - (?&Decimal) | (?&Decimal)
#(?&d) (?: - (?&d))?
)
(?P<N>
[sS]*?
)
)
'''
flags = regex.MULTILINE | regex.VERBOSE  #| regex.DOTALL  | regex.V1 #| regex.IGNORECASE | regex.UNICODE
pattern = regex.compile(pattern_string, flags=flags)
bk2 = f'''
ENTRY: 0.0975 - 0.101
'''.strip()
match = pattern.match('ENTRY: 0.0975 - 0.101')
match.groupdict()

给出:

{'entries': '0.0975', 'Decimal': None, 'Range': None, 'N': None}

它错过了第二个值。

> pip show regex
Name: regex
Version: 2022.1.18
Summary: Alternative regular expression module, to replace re.
Home-page: https://github.com/mrabarnett/mrab-regex
Author: Matthew Barnett
Author-email: regex@mrabarnett.plus.com
License: Apache Software License
Location: ...
Requires:
Required-by:
> python --version
Python 3.10.0

问题是,您在Decimal组模式中定义的空间被消耗掉了,而DEFINE模式是原子的,所以尽管最后一个[ ]*?部分是惰性的,可以匹配零次,但一旦匹配,就没有回头路了。如果将Decimal模式放入一个原子组中并比较两个模式,则可以检查此项。(?mx)^W*?ENTRYW*(?P<entries>(?>[ ]*? d+ (?:[.,] d+)? [ ]*?) - (?>[ ]*? d+ (?:[.,] d+)? [ ]*?) | (?>[ ]*? d+ (?:[.,] d+)? [ ]*?))使用DEFINE块公开与正则表达式相同的行为,而(?mx)^W*?ENTRYW*(?P<entries>[ ]*? d+ (?:[.,] d+)? [ ]*? - [ ]*? d+ (?:[.,] d+)? [ ]*? | [ ]*? d+ (?:[.,] d+)? [ ]*?)正确地找到匹配项。

最简单的解决方法是将可选的空间模式移动到Range组模式中。

你可能想在这里介绍其他一些小的增强功能:

  • 由于您只对捕获的子字符串感兴趣,因此不需要将regex.matchN组模式([sS]*?(一起使用,您可以使用regex.search并从正则表达式中删除N模式
  • 您不需要为类似a|a-b的模式使用组,您可以使用更高效的可选非捕获组方法a(?:-b)?

因此,正则表达式可以看起来像

^ W* ENTRY              W* (?P<entries>    (?&Range)    ) 
(?(DEFINE)
(?P<Decimal>
d+ (?:[.,] d+)?
)
(?P<Range>
(?&Decimal)(?: *- *(?&Decimal))*
)
)

​请参阅regex演示。

请参阅Python演示:

import regex
pattern_string =  r'''
^ W* ENTRY              W* (?P<entries>    (?&Range)    )
(?(DEFINE)
(?P<Decimal>
d+ (?:[.,] d+)?
)
(?P<Range>
(?&Decimal)(?: *- *(?&Decimal))?
)
)
'''
flags = regex.MULTILINE | regex.VERBOSE
pattern = regex.compile(pattern_string, flags=flags)
bk2 = f'''
ENTRY: 0.0975 - 0.101
'''.strip()
match = pattern.search('ENTRY: 0.0975 - 0.101')
print(match.groupdict())

输出:

{'entries': '0.0975 - 0.101', 'Decimal': None, 'Range': None}

最新更新