繁体   English   中英

重用正则表达式模式的一部分

[英]Reuse part of a Regex pattern

考虑这个(非常简化的)示例字符串:

1aw2,5cx7

如您所见,它是由逗号分隔的两位digit/letter/letter/digit值。

现在,我可以将其与以下内容进行匹配:

>>> from re import match
>>> match("\d\w\w\d,\d\w\w\d", "1aw2,5cx7")
<_sre.SRE_Match object at 0x01749D40>
>>>

问题是,我必须写\\d\\w\\w\\d两次。 对于小模式,这还不错,但是,对于更复杂的正则表达式,两次编写完全相同的内容会使最终模式变得庞大且难以处理。 这似乎也是多余的。

我尝试使用命名的捕获组:

>>> from re import match
>>> match("(?P<id>\d\w\w\d),(?P=id)", "1aw2,5cx7")
>>>

但它不起作用,因为它正在寻找1aw2两次出现,而不是digit/letter/letter/digit

有没有办法保存模式的一部分,例如\\d\\w\\w\\d ,以便以后可以在同一模式中使用它? 换句话说,我可以在模式中重用子模式吗?

不,当使用标准库re模块时,正则表达式模式不能被“符号化”。

你总是可以通过重用 Python 变量来做到这一点,当然:

digit_letter_letter_digit = r'\d\w\w\d'

然后使用字符串格式来构建更大的模式:

match(r"{0},{0}".format(digit_letter_letter_digit), inputtext)

或者,使用 Python 3.6+ f 字符串:

dlld = r'\d\w\w\d'
match(fr"{dlld},{dlld}", inputtext)

我经常使用这种技术从可重用的子模式中组合出更大、更复杂的模式。

如果你准备安装外部库,那么regex项目可以通过一个regex子程序调用来解决这个问题。 语法(?<digit>)重新使用已使用(隐式编号)捕获组的模式:

(\d\w\w\d),(?1)
^........^ ^..^
|           \
|             re-use pattern of capturing group 1  
\
  capturing group 1

您可以对命名捕获组执行相同操作,其中(?<groupname>...)是命名组groupname ,并且(?&groupname)(?P&groupname)(?P>groupname)重新使用匹配的模式groupname (后两种形式是与其他引擎兼容的替代形式)。

最后, regex支持(?(DEFINE)...)块来“定义”子例程模式,而无需它们在该阶段实际匹配任何内容。 您可以在该构造中放置多个(..)(?<name>...)捕获组,以便稍后在实际模式中引用它们:

(?(DEFINE)(?<dlld>\d\w\w\d))(?&dlld),(?&dlld)
          ^...............^ ^......^ ^......^
          |                    \       /          
 creates 'dlld' pattern      uses 'dlld' pattern twice

明确地说:标准库re模块不支持子程序模式。

注意:这将适用于PyPi regex module ,而不适用于re模块。

在您的情况下,您可以使用符号(?group-number)

(\d\w\w\d),(?1)

它相当于:

(\d\w\w\d),(\d\w\w\d)

请注意, \\w包括\\d 正则表达式将是:

(\d[a-zA-Z]{2}\d),(?1)

我被同样的问题困扰并写了这个片段

import nre
my_regex=nre.from_string('''
a=\d\w\w\d
b={{a}},{{a}}
c=?P<id>{{a}}),(?P=id)
''')
my_regex["b"].match("1aw2,5cx7")

由于缺乏更具描述性的名称,我将部分正则表达式命名为abc

访问它们就像{{a}}一样简单

import re
digit_letter_letter_digit = re.compile("\d\w\w\d") # we compile pattern so that we can reuse it later
all_finds = re.findall(digit_letter_letter_digit, "1aw2,5cx7") # finditer instead of findall
for value in all_finds:
    print(re.match(digit_letter_letter_digit, value))

既然你已经在使用 re,为什么不使用字符串处理来管理模式重复:

pattern = "P,P".replace("P",r"\d\w\w\d")

re.match(pattern, "1aw2,5cx7")

或者

P = r"\d\w\w\d"

re.match(f"{P},{P}", "1aw2,5cx7")

尝试使用反向引用,我相信它可以像下面这样匹配

1aw2,5cx7

你可以用

(\d\w\w\d),\1

请参阅此处以供参考http://www.regular-expressions.info/backref.html

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM