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:Pythonre
模块不支持递归模式。只有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")