我有下面的绳子:
'Well, I've tried to say "How Doth the Little Busy Bee," but it all came different!' Alice replied in a very melancholy voice. She continued, 'I'll try again.'
现在,我想摘录以下引文:
^{pr2}$我尝试了下面的代码,但我没有得到我想要的。[^\1]*
未按预期工作。或者问题在别处?在
import re
s = "'Well, I've tried to say \"How Doth the Little Busy Bee,\" but it all came different!' Alice replied in a very melancholy voice. She continued, 'I'll try again.'"
for i, m in enumerate(re.finditer(r'([\'"])(?!(?:ve|m|re|s|t|d|ll))(?=([^\1]*)\1)', s)):
print("\nGroup {:d}: ".format(i+1))
for g in m.groups():
print(' '+g)
这对pythonregex来说是一个很好的问题,因为在我看来,
re
模块是{a1}。这就是为什么对于Python中任何严肃的regex工作,我都会求助于matthewbarnett的stellarregex模块,它集成了Perl、PCRE和.NET的一些优秀特性。在我将向您展示的解决方案可以适应使用
re
,但是使用regex
更具可读性,因为它是模块化的。另外,将它作为更复杂的嵌套匹配的起始块,因为regex
允许您编写与Perl和PCRE中类似的recursive regular expressions。在好了,说够了,这里是代码(除了导入和定义只有四行)。请不要让长正则表达式吓到你:它很长,因为它是为可读而设计的。解释如下。在
代码
输出
^{pr2}$工作原理
首先,为了简化,请注意,我已经自由地将
I'll
转换为I will
,减少了引号的混淆。对I'll
进行寻址对于否定的lookahead是没有问题的,但是我想让regex可读。在在},这与定义变量或子例程以避免重复一样。在
(?(DEFINE)...)
块中,我们定义了三个子表达式qmark
、not_qmark
和{在定义块之后,我们继续匹配:
(?&a_quote)
匹配整个引号|
或者。。。在(?¬_qmark)?
匹配非引号的可选文本(?P<quote>(?&a_quote))
匹配一个完整的引号并将其捕获到quote
组中(?¬_qmark)?
匹配非引号的可选文本(?P=open)
与在引号开头捕获的引号匹配。在Python代码只需要打印匹配项和
quote
捕获组(如果存在的话)。在这个可以精炼吗?当然。以这种方式使用
(?(DEFINE)...)
,可以构建漂亮的模式,以后可以重新阅读和理解。在添加递归
如果您想使用纯正则表达式处理更复杂的嵌套,则需要使用递归。在
要添加递归,只需定义一个组并使用子例程语法引用它。{23>在组内执行代码。要在组
something
中执行代码,请使用(?&something)
。记住,通过使递归成为可选的(?
)或交替的一侧,为引擎留下一个出口。在参考文献
如果您真的需要从一个只应用一次的正则表达式返回所有结果,那么就需要使用lookahead(
(?=findme)
),以便查找位置在每次匹配之后返回到开始位置—请参见this answer以获得更详细的解释。在为了防止错误匹配,还需要一些关于增加复杂性的引号的子句,例如
I've
中的撇号不应算作左引号或右引号。没有一种明确的方法可以做到这一点,但我坚持的原则是:A"
不算开首引号,但,"
可以算。在应用上述规则将得到以下正则表达式:
Debuggex Demo
对于任何可能的候选正则表达式,一个很好的快速健全性检查测试是反转引号。这已经在演示中完成了:https://regex101.com/r/vX4cL9/1
编辑
我修改了正则表达式,它与更复杂的情况匹配:
DEMO
现在更复杂了,主要的改进是不直接匹配一些标点符号(
[!?.]
)和更好的引号大小写分隔。通过各种实例进行验证。在句子将在
content
捕获组中。当然,它有一些限制,与空格的使用有关,等等,但是它应该适用于大多数格式正确的句子,或者至少可以用于示例。在(?=(?<!\w|[!?.])('|\")(?!\s)
-匹配'
或{(?<!\w|[!?.])
)或不带空格((?!\s)
)的'
或{(?P<content>(?:.(?!(?<=(?=\1).)(?!\w)))*)\1(?!\w))
-匹配句子,后跟 与开始时相同的字符('
或{它不直接匹配整个句子,但是由于捕捉组嵌套在lookaround结构中,所以使用全局匹配修饰符,它也将匹配句子中的句子-因为它只直接匹配句子开始之前的位置。在
关于您的regex:
我想,
[^\1]*
你指的是任何字符,但不是组1中捕获的字符,但character类不是这样工作的,因为它将\1
作为八进制表示法中的字符(我认为这是某种空白)而不是对捕获组的引用。看看this example-阅读说明。还要比较THIS和THIS正则表达式的匹配。在为了达到您想要的效果,您应该使用lookaround,类似这样的方法:^{} -捕获开始字符,然后匹配每个不紧跟捕获的开始字符的字符,然后再捕获一个字符,它直接位于捕获的字符之前-并且您在排除的字符之间有完整的内容。在
相关问题 更多 >
编程相关推荐