具有不同量词的正则表达式捕获组

Posted

技术标签:

【中文标题】具有不同量词的正则表达式捕获组【英文标题】:Regex capture group with different quantifiers 【发布时间】:2020-10-22 04:35:50 【问题描述】:

我正在解析的文本包括捕获组前后以及捕获组内的星号。我已经确定解析捕获组的模式基本上是:文本之前的连续星号将始终至少为 30。同样,最后一个单词之后的连续星号将至少为 15 个字符长。捕获组中的连续星号将始终小于 10。我遇到的问题是我不确定如何为捕获组中的星号与组中的其他字符提供不同的量词,但将其包含在相同的匹配集。例如:

text = 'ÿÿÿÿ*************************************************CURRICULUM VITAE***Información *personal*********************ìÌ**Ì*Ì*Ì*'

所以基本上,我只需要捕获文本部分。星号可以存在于实际文本之前和之后(我可以稍后删除),但乱码不能。所以任一输出都有效:

#Output #1 
CURRICULUM VITAE***Información *personal
#output #2
**********CURRICULUM VITAE***Información *personal**********

以下是我尝试过的无法区分捕获组和后续乱码的代码。不过,它确实可以正确识别文本之前的星号。

p=re.compile(r'(?<=[*]30)([\x29,10|\u00c0-\u00d6|\u00d8-\u00f6|\u00f8-\u02af|\u1d00-\u1d25|\u1d62-\u1d65|\u1d6b-\u1d77|\u1d79-\u1d9a|\u1e00-\u1eff|\u2090-\u2094|\u2184-\u2184|\u2488-\u2490|\u271d-\u271d|\u2c60-\u2c7c|\u2c7e-\u2c7f|\ua722-\ua76f|\ua771-\ua787|\ua78b-\ua78c|\ua7fb-\ua7ff|\ufb00-\ufb06|\x20-\x2A|\x2B-\x7E]+)(?=[*],15)', re.MULTILINE)

print(re.findall(p, text)[0])

#output
*******************CURRICULUM VITAE***Información *personal*********************ìÌ**Ì*Ì*Ì*

如您所见,它成功地切断了实际捕获组之前的乱码,但没有切断捕获组之后的乱码。我猜上面的正则表达式没有正确编写,因此 \x29,10 与其余字符一起执行,这些字符可能有 + 出现。

请注意,\x29 是 * 的 unicode。更改 unicode 字符作为解析捕获组的一种方式不是一种选择,我需要能够保持重音,这也可能存在于乱码部分。

根据 MA​​X XAPI 的评论编辑

在乱码之后可能存在 15 个以上的连续星号,因此对于您的代码,它似乎在最后 15 个以上的连续星号处被删除,但保留了先验。所以我需要的是比赛要么在前 15 个连续的星号处切割(即,在捕获组之后没有星号),要么只在捕获组之后包括前 15 个星号。例如:

p=re.compile(r'(?<=[*]30)([^*][\x2A,10|\u00c0-\u00d6|\u00d8-\u00f6|\u00f8-\u02af|\u1d00-\u1d25|\u1d62-\u1d65|\u1d6b-\u1d77|\u1d79-\u1d9a|\u1e00-\u1eff|\u2090-\u2094|\u2184-\u2184|\u2488-\u2490|\u271d-\u271d|\u2c60-\u2c7c|\u2c7e-\u2c7f|\ua722-\ua76f|\ua771-\ua787|\ua78b-\ua78c|\ua7fb-\ua7ff|\ufb00-\ufb06|\x20-\x2A|\x2B-\x7E]+[^*])(?=[*]15,)',re.MULTILINE)

text=t='ÿÿÿÿ*************************************************CURRICULUM VITAE***Información *personal**********************ìÌ**Ì*Ì*Ì*************************************(ìÌ**Ì*Ì*Ì***************'

#output
print(re.findall(p, text))
['CURRICULUM VITAE***Información *personal**********************ìÌ**Ì*Ì*Ì']

#desired output
['CURRICULUM VITAE***Información *personal']
The following is also acceptable
['CURRICULUM VITAE***Información *personal***************']

【问题讨论】:

【参考方案1】:

这仅使用一个否定的前瞻断言:

试试:

\*30,((?:[^*]|\*(?!\*9))+?)\*15,

Regex Demo

    \*30, 匹配 30 个或更多星号 ( 捕获组 1 的开始 (?:[^*]|\*(?!\*9))+? 匹配非捕获组中的一个或多个:非星号或后面不带 9 个星号的星号 `)' 捕获组 1 结束 \*15, 匹配 15 个或更多星号
import re

text = 'ÿÿÿÿ*************************************************CURRICULUM VITAE***Información *personal*********************ìÌ**Ì*Ì*Ì*'

l = re.findall(r'\*30,((?:[^*]|\*(?!\*9))+?)\*15,', text)
print(l)

打印:

['CURRICULUM VITAE***Información *personal']

【讨论】:

【参考方案2】:

考虑到捕获组必须以 * 以外的其他名称开头并且必须以相同的方式结束,您可以使用一个技巧。因此,只需添加另一个包含两个 [^*] 的容器组:

(?<=[*]30)([^*][\x29,10|\u00c0-\u00d6|\u00d8-\u00f6|\u00f8-\u02af|\u1d00-\u1d25|\u1d62-\u1d65|\u1d6b-\u1d77|\u1d79-\u1d9a|\u1e00-\u1eff|\u2090-\u2094|\u2184-\u2184|\u2488-\u2490|\u271d-\u271d|\u2c60-\u2c7c|\u2c7e-\u2c7f|\ua722-\ua76f|\ua771-\ua787|\ua78b-\ua78c|\ua7fb-\ua7ff|\ufb00-\ufb06|\x20-\x2A|\x2B-\x7E]+[^*])(?=[*]15,)

我已添加/更改:

在捕获组的末尾和开头添加了两次“非*”:([^*] ... [^*]) 在结束时将 ,15 更改为 15,(因此“至少出现 15 次”而不是“最多出现 15 次”)

https://regex101.com/r/m6lqP3/3

【讨论】:

看到这个Regex Demo。你不应该接受这个,因为有 10 个或更多的 '*'。

以上是关于具有不同量词的正则表达式捕获组的主要内容,如果未能解决你的问题,请参考以下文章

具有多个捕获组的 R 中的正则表达式组捕获

为啥我的正则表达式组量词不起作用?

正则表达式 Python / 组量词

使用带有不情愿、贪婪和所有格量词的捕获组

量词可以用于R中的正则表达式替换吗?

具有捕获组的有效正则表达式,但 sed 脚本不起作用