我的代码中有一些这样的结构:
from pyparsing import Char, srange
_any_char = Char(srange('[\x00-\U0010FFFF]'))
范围的生成非常慢,即使在相对不错的机器上使用 Python 3.12,也需要 6-8 秒(哈?)。
为什么会发生这种情况?我应该用什么来替换它们?
srange()
函数 的样子(已删除文档字符串):
_charRange = Group(_singleChar + Suppress("-") + _singleChar)
_reBracketExpr = (
Literal("[")
+ Opt("^").set_results_name("negate")
+ Group(OneOrMore(_charRange | _singleChar)).set_results_name("body")
+ Literal("]")
)
def srange(s: str) -> str:
_expanded = (
lambda p: p
if not isinstance(p, ParseResults)
else "".join(chr(c) for c in range(ord(p[0]), ord(p[1]) + 1))
)
try:
return "".join(_expanded(part) for part in _reBracketExpr.parse_string(s).body)
except Exception as e:
return ""
正如你(或我)所看到的,
pyparsing
正在使用_reBracketExpr
解析参数,它本身就是一个pyparsing
表达式,然后将结果传递给_expanded
。如果 _expanded
是 p
(范围),ParseResult
将创建一个新字符串,否则返回 p
不变(单个字符)。最后,所有这些字符串都连接起来,创建一个更大的字符串。
在您(或我)的情况下,每个
Char(srange())
创建一个 0x10FFFF
- 0x80
+ 1
= ~1.1m
字符串。幸运的是,由于只有一个元素,因此会重用该字符串而不是连接来创建最终结果。您(或我)可以通过运行来确认这一点:
print(''.join((a := 'c' * 100000) for e in [0]) is a) # True, at least on Python 3.12
Regex
(在引擎盖下使用本机 re
):
_any_char = Regex(r'[\x80-\U0010FFFF]') # With or without r are both fine.
没有创建巨大的字符串,希望与正常的字符串一样高效
Char
。