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

问题描述

我要解析的文本在捕获组之前和之后以及捕获组中都包含星号。我确定的用于解析捕获组的模式基本上是:文本之前的连续星号始终至少为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字符作为解析捕获组的方法不是一种选择,我需要能够保留可能在乱码部分也存在的重音符号。

编辑MAX 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***************']

解决方法

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

(?<=[*]{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

,

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

尝试:

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

Regex Demo

  1. \*{30,}匹配30个或更多星号
  2. (开始捕获组1
  3. (?:[^*]|\*(?!\*{9}))+?匹配以下非捕获组中的一个或多个:非星号或不跟随9个星号的星号
  4. `)'捕获组1的结尾
  5. \*{15,}匹配15个或更多的星号
import re

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

l = re.findall(r'\*{30,}',text)
print(l)

打印:

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