我有一个表单的正则表达式
def parse(self, format_string):
for m in re.finditer(
r"""(?: \$ \( ( [^)]+ ) \) ) # the field access specifier
| (
(?:
\n | . (?= \$ \( ) # any one single character before the '$('
)
| (?:
\n | . (?! \$ \( ) # any one single character, except the one before the '$('
)*
)""",
format_string,
re.VERBOSE):
...
我想用一些自定义速记“常量”替换所有重复序列(
\$ \(
),如下所示:def parse(self, format_string):
re.<something>('\BEGIN = \$\(')
for m in re.finditer(
r"""(?: \BEGIN ( [^)]+ ) \) ) # the field access specifier
| (
(?:
\n | . (?= \BEGIN ) # any one single character before the '$('
)
| (?:
\n | . (?! \BEGIN ) # any one single character, except the one before the '$('
)*
)""",
format_string,
re.VERBOSE):
...
有没有办法用正则表达式本身来做到这一点(即不使用 Python 的字符串格式将
\BEGIN
替换为 \$\(
)?澄清: Python 源代码仅用于上下文和说明。我正在寻找 RE 解决方案,该解决方案在某些 RE 方言(可能不是 Python 的方言)中可用,而不是专门针对 Python 的解决方案。
最佳答案
我认为这在 Python 的正则表达式风格中是不可能的。您将需要仅由 PCRE 支持的递归(或更确切地说是模式重用)。事实上,PCRE 甚至在其 man page 中提到了定义速记是如何工作的。 (搜索“定义子模式”)。
在 PCRE 中,您可以以与反向引用类似的方式使用递归语法 - 除了再次应用该模式,而不是尝试从反向引用获取相同的文字文本。例子:
/(\d\d)-(?1)-(?1)/
匹配日期之类的东西(其中
(?1)
将被替换为 \d\d
并再次评估)。这真的很强大,因为如果您在引用组本身中使用此构造,您将获得递归 - 但我们在这里甚至不需要它。以上也适用于命名组:/(?<my>\d\d)-(?&my)-(?&my)/
现在我们已经很接近了,但定义也是模式的第一次使用,这使表达式有些困惑。诀窍是首先在从未评估过的位置使用模式。手册页建议了一个依赖于(不存在的)组的条件
DEFINE
:/
(?(DEFINE)
(?<my>\d\d)
)
(?&my)-(?&my)-(?&my)
/x
构造
(?(group)true|false)
适用模式 true
若群group
之前使用过,和(可选)模式 false
除此以外。由于没有组DEFINE
,条件将始终为假,并且 true
模式将被跳过。因此,我们可以将各种定义放在那里,而不必担心它们会被应用并弄乱我们的结果。这样我们就可以让它们进入模式,而无需真正使用它们。而替代方案是一个负前瞻,它永远不会到达定义表达式的点:
/
(?!
(?!) # fail - this makes the surrounding lookahead pass unconditionally
# the engine never gets here; now we can write down our definitions
(?<my>\d\d)
)
(?&my)-(?&my)-(?&my)
/x
但是,如果您没有条件,但确实有命名模式重用(我认为不存在这样的风格),那么您只需要这种形式。另一个变体的优点是使用
DEFINE
使组的用途一目了然,而前瞻方法有点模糊。所以回到你原来的例子:
/
# Definitions
(?(DEFINE)
(?<BEGIN>[$][(])
)
# And now your pattern
(?: (?&BEGIN) ( [^)]+ ) \) ) # the field access specifier
|
(
(?: # any one single character before the '$('
\n | . (?= (?&BEGIN) )
)
|
(?: # any one single character, except the one before the '$('
\n | . (?! (?&BEGIN) )
)*
)
/x
这种方法有两个主要注意事项:
(?<myPattern>a(b)c)
的东西并重复使用它,b
永远不会被捕获——当重用一个模式时,所有的组都是非捕获的。 然而,与任何类型的插值或串联相比,最重要的优势是,您永远不会产生无效模式,并且您也不会弄乱您的捕获组计数。
关于regex - 有没有办法在正则表达式中定义自定义速记?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/18149814/