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

Python 重用正则表达式模式的一部分,python,regex,Python,Regex,考虑以下(非常简化的)示例字符串: 1aw2,5cx7 如您所见,它是两个由逗号分隔的数字/字母/字母/数字值 现在,我可以将其与以下内容相匹配: >>> from re import match >>> match("\d\w\w\d,\d\w\w\d", "1aw2,5cx7") <_sre.SRE_Match object at 0x01749D40> >>> 但它没有工作,因为它正在查找两个出现的1aw2,而不是数字/

考虑以下(非常简化的)示例字符串:

1aw2,5cx7
如您所见,它是两个由逗号分隔的
数字/字母/字母/数字

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

>>> from re import match
>>> match("\d\w\w\d,\d\w\w\d", "1aw2,5cx7")
<_sre.SRE_Match object at 0x01749D40>
>>>
但它没有工作,因为它正在查找两个出现的
1aw2
,而不是
数字/字母/字母/数字


是否有任何方法可以保存模式的一部分,例如
\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)
我经常使用这种技术从可重用的子模式组成更大、更复杂的模式

如果准备安装外部库,则可以使用解决方案解决此问题。语法
(?)
重新使用已使用(隐式编号)捕获组的模式:

(\d\w\w\d),(?1)
^........^ ^..^
|           \
|             re-use pattern of capturing group 1  
\
  capturing group 1
您可以对命名捕获组执行相同的操作,其中
(?…)
是命名组
groupname
(?&groupname)
(?p&groupname)
(?p>groupname)
重复使用
groupname
匹配的模式(后两种形式是与其他引擎兼容的替代形式)

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

(?(DEFINE)(?<dlld>\d\w\w\d))(?&dlld),(?&dlld)
          ^...............^ ^......^ ^......^
          |                    \       /          
 creates 'dlld' pattern      uses 'dlld' pattern twice
(?(定义)(?\d\w\w\d))(?&dlld),(?&dlld)
^...............^ ^......^ ^......^
|                    \       /          
创建“dlld”模式使用“dlld”模式两次

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

尝试使用反向引用,我相信它的工作原理与下面类似

1aw2,5cx7
你可以用

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

请参见此处以获取参考

注意:这将与
re
模块一起使用。

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

(\d\w\w\d),(?1)
这相当于:

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

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

我也遇到了同样的问题,于是写了

导入nre
my_regex=nre.from_字符串(“”)
a=\d\w\w\d
b={{a},{a}
c=?P{{a}),(?P=id)
''')
my_regex[“b”]匹配(“1aw2,5cx7”)
由于缺少更具描述性的名称,我将部分正则表达式命名为
a
b
c


访问它们就像
{{a}}

一样简单,因为您已经在使用re,为什么不使用字符串处理来管理模式重复:

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))
pattern = "P,P".replace("P",r"\d\w\w\d")

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


谢谢你的回答,但这在我的情况下是行不通的。使用
\1
将查找两次出现的
1aw2
。我希望出现两次
\d\w\w\d
,而不考虑数字/字母。与编号组匹配的文本相匹配。它没有重复使用该模式。太糟糕了:-(这是一个PCRE功能,我想Python可以识别它。对于命名的捕获组,使用
(?&name)
。可选的形式是
(?P>name
)和
(?P&name)
也受支持。
regex
很棒!是的!PyPI上的
regex
模块很棒!这个答案也很棒+1@iCodez而是使用命名组,例如
(?'digitletters'\d\w\d),(?&digitletters)
不是实际“符号化模式”的方法并在正则表达式中分解它们?如果是,也许你可以将其标记为已接受,否则人们会一直认为没有办法这么做。@iago lito:Python
re
模块不支持递归模式。只有
regex
支持。请注意,你不能在他们没有参与的答案的注释中ping OP。啊,okay、 感谢您的澄清:)也许至少值得通知读者PCRE支持它?我来到这篇文章的时候并没有专门寻找python风格的正则表达式解决方案。@iago lito:我不太明白这一点。这个问题是关于Python及其标准库
re
模块的,而不是一般的正则表达式引擎。引擎之间有太多的变化,没有一个标准的正则表达式语法。你最好去一个专门从事跟踪的网站。那是相当不可读的。为什么不使用字符串替换?@Martijn Pieters,你说得对。事实上,使用re.sub()并不像我写的那样有效,因为正在处理正则表达式特殊字符,而不是简单地替换源代码。
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))
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")