我有一个表格的正则表达式
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):
...
Run Code Online (Sandbox Code Playgroud)
我想\$ \(用一些自定义简写"常量" 替换所有重复序列(),如下所示:
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):
...
Run Code Online (Sandbox Code Playgroud)
有没有一种方法(即不使用Python的字符串格式化来代替用正则表达式本身做这个\BEGIN用\$\()?
澄清: Python源代码纯粹用于上下文和插图.我正在寻找RE解决方案,它可以在一些RE方言中使用(可能不是Python的方言),而不是专门针对Python的解决方案.
我不认为这在Python的正则表达式中是可行的.您需要递归(或者说模式重用),这只是PCRE支持的.事实上,PCRE甚至提到了如何在其手册页中定义缩写词(搜索"定义子模式").
在PCRE中,您可以以类似于反向引用的方式使用递归语法 - 除了再次应用模式,而不是尝试从反向引用获取相同的文本文本.例:
/(\d\d)-(?1)-(?1)/
Run Code Online (Sandbox Code Playgroud)
匹配日期之类的东西((?1)将被替换为,\d\d并再次评估).这非常强大,因为如果你在引用的组本身中使用这个构造,你会得到递归 - 但我们甚至不需要这里.以上也适用于命名组:
/(?<my>\d\d)-(?&my)-(?&my)/
Run Code Online (Sandbox Code Playgroud)
现在我们已经非常接近,但是这个定义也是该模式的第一次使用,这有点混淆了表达式.诀窍是首先在永不评估的位置使用模式.手册页建议一个依赖于(不存在的)组的条件DEFINE:
/
(?(DEFINE)
(?<my>\d\d)
)
(?&my)-(?&my)-(?&my)
/x
Run Code Online (Sandbox Code Playgroud)
如果之前使用了组,则构造(?(group)true|false)应用模式,true否则group使用(可选)模式false.由于没有组DEFINE,条件将始终为false,并且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
Run Code Online (Sandbox Code Playgroud)
但是,你只需要这个表单,如果你没有条件,但确实有命名模式重用(我不认为这样的味道存在).另一个变体的优点是,使用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
Run Code Online (Sandbox Code Playgroud)
这种方法有两个主要的注意事项:
(?<myPattern>a(b)c)并重复使用它,b则永远不会捕获 - 当重用模式时,所有组都是非捕获的.然而,与任何类型的插值或连接相比,最重要的优点是,您永远不会产生无效的模式,并且您也不会弄乱您的捕获组计数.
| 归档时间: |
|
| 查看次数: |
269 次 |
| 最近记录: |