无法使用 PyPi 正则表达式包将数字范围与 DEFINE 块中声明的模式匹配
Failing to match number ranges with pattern declared in DEFINE block using PyPi regex package
我正在使用 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>
[\s\S]*?
)
)
'''
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
组模式中定义的space被消耗了,而DEFINE
模式是原子的,所以虽然最后的[ ]*?
部分是惰性的,可以匹配零次,一旦匹配,就没有回头路了。如果将 Decimal
模式放入原子组并比较两个模式,则可以检查这一点,参见。 this regex demo and this regex demo。 (?mx)^\W*?ENTRY\W*(?P<entries>(?>[ ]*? \d+ (?:[.,] \d+)? [ ]*?) - (?>[ ]*? \d+ (?:[.,] \d+)? [ ]*?) | (?>[ ]*? \d+ (?:[.,] \d+)? [ ]*?))
使用 DEFINE
块公开与正则表达式相同的行为,而 (?mx)^\W*?ENTRY\W*(?P<entries>[ ]*? \d+ (?:[.,] \d+)? [ ]*? - [ ]*? \d+ (?:[.,] \d+)? [ ]*? | [ ]*? \d+ (?:[.,] \d+)? [ ]*?)
正确找到匹配项。
最简单的解决方法是将可选的 space 模式移动到 Range
组模式中。
您可能还想在此处介绍其他小的增强功能:
- 由于您只对捕获的子字符串感兴趣,因此不需要使用
regex.match
和 N
组模式 ([\s\S]*?
),您可以使用 regex.search
并从正则表达式 中删除 N
模式
- 你不需要为
a|a-b
这样的模式使用组,你可以使用更有效的可选 non-capturing 组方法,a(?:-b)?
.
所以,正则表达式可以看起来像
^ \W* ENTRY \W* (?P<entries> (?&Range) )
(?(DEFINE)
(?P<Decimal>
\d+ (?:[.,] \d+)?
)
(?P<Range>
(?&Decimal)(?:\ *-\ *(?&Decimal))*
)
)
参见 regex demo.
参见 Python demo:
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}
我正在使用 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>
[\s\S]*?
)
)
'''
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
组模式中定义的space被消耗了,而DEFINE
模式是原子的,所以虽然最后的[ ]*?
部分是惰性的,可以匹配零次,一旦匹配,就没有回头路了。如果将 Decimal
模式放入原子组并比较两个模式,则可以检查这一点,参见。 this regex demo and this regex demo。 (?mx)^\W*?ENTRY\W*(?P<entries>(?>[ ]*? \d+ (?:[.,] \d+)? [ ]*?) - (?>[ ]*? \d+ (?:[.,] \d+)? [ ]*?) | (?>[ ]*? \d+ (?:[.,] \d+)? [ ]*?))
使用 DEFINE
块公开与正则表达式相同的行为,而 (?mx)^\W*?ENTRY\W*(?P<entries>[ ]*? \d+ (?:[.,] \d+)? [ ]*? - [ ]*? \d+ (?:[.,] \d+)? [ ]*? | [ ]*? \d+ (?:[.,] \d+)? [ ]*?)
正确找到匹配项。
最简单的解决方法是将可选的 space 模式移动到 Range
组模式中。
您可能还想在此处介绍其他小的增强功能:
- 由于您只对捕获的子字符串感兴趣,因此不需要使用
regex.match
和N
组模式 ([\s\S]*?
),您可以使用regex.search
并从正则表达式 中删除 - 你不需要为
a|a-b
这样的模式使用组,你可以使用更有效的可选 non-capturing 组方法,a(?:-b)?
.
N
模式
所以,正则表达式可以看起来像
^ \W* ENTRY \W* (?P<entries> (?&Range) )
(?(DEFINE)
(?P<Decimal>
\d+ (?:[.,] \d+)?
)
(?P<Range>
(?&Decimal)(?:\ *-\ *(?&Decimal))*
)
)
参见 regex demo.
参见 Python demo:
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}