gpt4 book ai didi

python - 部分正则表达式匹配

转载 作者:太空宇宙 更新时间:2023-11-03 15:02:39 25 4
gpt4 key购买 nike

我在询问 Python 中的部分正则表达式匹配。

例如:

如果你有一个字符串:

string = 'foo bar cat dog elephant barn yarn p n a'

还有一个正则表达式:

pattern = r'foo bar cat barn yard p n a f'

以下为真:

  • re.match(pattern, string) 将返回 None
  • re.search(pattern, string) 也会返回 None

尽管我们都可以看到模式的第一部分匹配字符串的第一部分。

所以不是搜索字符串中的整个模式,有没有办法查看字符串与模式匹配的百分比?

最佳答案

是的,可以进行部分正则表达式匹配

我一直在研究部分匹配的想法,并在搜索过程中找到了这个 Q。我找到了一种方法来做我需要做的事情,我想我会把它贴在这里。

这不是速度恶魔。可能仅在速度不是问题的情况下才有用。

此函数找到正则表达式的最佳部分匹配并返回匹配文本。

>>> def partial_match(regex, string, flags=0, op=re.match):
... """
... Matches a regular expression to a string incrementally, retaining the
... best substring matched.
... :param regex: The regular expression to apply to the string.
... :param string: The target string.
... :param flags: re module flags, e.g.: `re.I`
... :param op: Either of re.match (default) or re.search.
... :return: The substring of the best partial match.
... """
... m = op(regex, string, flags)
... if m:
... return m.group(0)
... final = None
... for i in range(1, len(regex) + 1):
... try:
... m = op(regex[:i], string, flags)
... if m:
... final = m.group(0)
... except re.error:
... pass
... return final
...

测试:

>>> partial_match(r".*l.*?iardvark", "bluebird")
'bluebi'
>>>
>>> partial_match(r"l.*?iardvark", "bluebird")
>>> # None was returned. Try again with search...
>>>
>>> partial_match(r"l.*?iardvark", "bluebird", op=re.search)
'luebi'
>>>
>>> string = 'foo bar cat dog elephant barn yarn p n a'
>>> pattern = r'foo bar cat barn yard p n a f'
>>>
>>> partial_match(pattern, string)
'foo bar cat '
>>>
>>> partial_match(r".* (zoo){1,3}ran away", "the fox at the "
... "zoozoozoozoozoo is "
... "happy")
'the fox at the zoozoozoo'

表现如预期。该算法不断尝试将尽可能多的表达式与目标字符串匹配。它一直持续到整个表达式与目标字符串匹配为止,保留最佳的部分匹配。

好的。现在让我们看看它到底有多慢......

>>> import cProfile as cprof, random as rand, re
>>>
>>> # targets = ['lazy: that# fox~ The; little@ quick! lamb^ dog~ ',
>>> # << 999 more random strings of random length >>]
>>>
>>> words = """The; quick! brown? fox~ jumped, over. the! lazy: dog~
... Mary? had. a little- lamb, a& little@ lamb^ {was} she... and,,,
... [everywhere] that# Mary* went=, the. "lamb" was; sure() (to) be.
... """.split()
...
>>> targets = [' '.join(rand.choices(words, k=rand.randint(1, 100)))
... for _ in range(1000)]
...
>>> exprs = ['.*?&', '.*(jumped|and|;)', '.{1,100}[\\.,;&#^]', '.*?!',
... '.*?dog. .?lamb.?', '.*?@', 'lamb', 'Mary']
...
>>> partial_match_script = """
... for t in targets:
... for e in exprs:
... m = partial_match(e, t)
... """
...
>>> match_script = """
... for t in targets:
... for e in exprs:
... m = re.match(e, t)
... """
...
>>> cprof.run(match_script)
32003 function calls in 0.032 seconds
>>>
>>> cprof.run(partial_match_script)
261949 function calls (258167 primitive calls) in 0.230 seconds

re.match() 直接运行它,它只需要进行常规匹配并且大部分时间都失败可能不是函数性能的公平比较.更好的比较是与支持模糊匹配的模块进行比较,我在下面做了这样的事情……而且该功能毕竟没问题。

可以使用 re.sre_parse 和/或 re.sre_compile 模块开发性能更高的解决方案。看起来所有要引用的文档都在源代码和网络上的零碎信息中,如 https://www.programcreek.com/python/example/1434/sre_parse

对于这些模块,我认为可能有一种方法可以通过标记或子表达式逐步应用正则表达式,而不是像我所做的那样通过单个字符。

此外,正如有人评论的那样,regex 包具有模糊匹配功能 ( https://pypi.org/project/regex/ ) - 但它的行为略有不同,并且可能允许部分匹配中出现意外字符。

>>> import regex
>>>
>>> regex.match(r"(?:a.b.c.d){d}", "a.b.c", regex.ENHANCEMATCH).group(0)
'a.b.c'
>>> regex.match(r"(?:moo ow dog cat){d}", "moo cow house car").group(0)
'moo c'
>>> regex.match(r"(?:moo ow dog cat){d}", "moo cow house car",
... regex.ENHANCEMATCH).group(0)
...
'moo c'
>>> # ^^ the 'c' above is not what we want in the output. As you can see,
>>> # the 'fuzzy' matching is a bit different from partial matching.
>>>
>>> regex_script = """
... for t in targets:
... for e in exprs:
... m = regex.match(rf"(?:{e}){{d}}", t)
... """
>>>
>>> cprof.run(regex_script)
57912 function calls (57835 primitive calls) in 0.180 seconds
...
>>> regex_script = """
... for t in targets:
... for e in exprs:
... m = regex.match(rf"(?:{e}){{d}}", t, flags=regex.ENHANCEMATCH)
... """
>>>
>>> cprof.run(regex_script)
57904 function calls (57827 primitive calls) in 0.298 seconds

性能比没有 regex.ENHANCEMATCH 标志的 partial_match() 解决方案好一点。但是,带有标志的速度较慢。

带有 regex.BESTMATCH 标志的正则表达式在行为上可能与 partial_match() 最相似,但它甚至更慢:

>>> regex_script = """
... for t in targets:
... for e in exprs:
... m = regex.match(rf"(?:{e}){{d}}", t, flags=regex.BESTMATCH)
... """
>>> cprof.run(regex_script)
57912 function calls (57835 primitive calls) in 0.338 seconds

regex 也有一个 partial=True 标志,但这似乎根本不像我们预期的那样起作用。

关于python - 部分正则表达式匹配,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/36145045/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com