Regex故障排除,无法使用原子类忽略特定字符

问题描述 投票:1回答:2

在我只有一个字母的字符串中,我试图找到某个图案GYG的相邻字符,并达到一定深度dep。但是,如果在达到所需深度之前找到字符Y,则正则表达式引擎应中断并返回在GYGY之间找到的所有字符。

以说明:

  • 对于dep = 2中的XXXGYGXXXYXGYGXX,所需的匹配为XXXXX XX
  • 对于dep = 3中的XXXGYGXXXYXGYGXX,所需的匹配为XXXXXXX XX

我使用的表达式:(?:GYG|Y)(*SKIP)(*FAIL)|(?<=GYG)\w{1,dep}(?=Y)|(?<=GYG)\w{1,dep}|(?<=Y)\w{1,dep}(?=GYG)|\w{dep}(?=GYG)其中dep是用户定义的。

使用这个玩具示例,我的正则表达式工作正常。但是,使用我的真实字符串(如下所示)却没有。我怀疑原子团(?<=Y)\w{1,dep}(?=GYG)|\w{dep}(?=GYG)发生了什么事,但我似乎无法弄清楚哪里。

我的代码:

import regex as re 
ls = []
regex = '(?:GYG)(*SKIP)(*FAIL)|(?<=GYG)\w{1,3}(?=Y)|(?<=GYG)\w{1,3}|(?<=Y)\w{1,3}|\w{1,3}?(?=GYG)'
seq = 'MASNDYTQQATQSYGAYPTQPGQGYSQQSSQPYGQQSYSGYSQSTDTSGYGQSSYSSYGQSQNTGYGTQSTPQGYGSTGGYGSSQSSQSSYGQQSSYPGYGQQPAPSSTSGSYGSSSQSSSYGQPQSGSYSQQPSYGGQQQSYGQQQSYNPPQGYGQQNQYNS'
for matchedobj in re.finditer(regex, seq):
    ls.append(matchedobj.group(0))

输出:

['DTS', 'QSS', 'QNT', 'TQS', 'TPQ', 'STG', 'SSQ', 'SYP', 'QQP', 'PPQ', 'QQN']

Regex101 Link

python regex regex-negation
2个回答
1
投票

[这里的挑战是,取反的模式GYG是对称的,它在两侧G上均包含Y字符。因此,出于各种原因,积极的环顾四周行不通。

有两种方法可以解决这个问题。首先,是使用环顾四周。

第一种方法:环顾四周方法

要设置关于GYG主题的环顾四周,但仍捕获独立的G字符,我们首先取反all G字符。由于Y字符也不应该被捕获,因此我们将GY都放在否定的类[^YG]中。这将为我们提供G(?<!GYG)(?!YG)所提供的周围环境,并在下面逐步介绍@The第四只鸟。请看一下他的回答。

技巧是使用G重新捕获最初被否定类跳过的G(?<!GYG)(?!YG)字符。这样可以确保仍捕获G和`YG模式中的GY字符以及独立的字符。

regex = (?:(?:[^\WYG]|G(?<!GYG)(?!YG)){1,3}+(?=GYG)|(?<=GYG)(?:[^\WYG]|G(?<!GYG)(?!YG)){1,3}+)

由于我们想在GYG的两侧进行捕获,因此第一个交替是正向向前(?=GYG)。对正向后视(?<=GYG)

重复相同的步骤

第一种方法的代码:

import regex as re 
ls = []
seq = 'MASNDYTQQATQSYGAYPTQPGQGYSQQSSQPYGQQSYSGYSQSTDTSGYGQSSYSSYGQSQNTGYGTQSTPQGYGSTGGYGSSQSSQSSYGQQSSYPGYGQQPAPSSTSGSYGSSSQSSSYGQPQSGSYSQQPSYGGQQQSYGQQQSYNPPQGYGQQNQYNS'
regex = (?:(?:[^\WYG]|G(?<!GYG)(?!YG)){1,3}+(?=GYG)|(?<=GYG)(?:[^\WYG]|G(?<!GYG)(?!YG)){1,3}+)
for matchedobj in re.finditer(regex, seq):
    ls.append(matchedobj.group(0)) 

第二种方法:在GYG处锚定

[第二种方法由另一个用户向我建议:Wiktor。解决方案here。 regex表达式查找所有GYG模式。然后使用贪婪的?量词进行扩展。

regex = ((?:(?!GYG)[^Y]){1,3})?GYG((?:(?!GYG)[^Y]){1,3})?

此方法的唯一“不足之处在于,它需要对组进行更多记账。

第二种方法的代码:

import regex as re 
ls = []
seq = 'MASNDYTQQATQSYGAYPTQPGQGYSQQSSQPYGQQSYSGYSQSTDTSGYGQSSYSSYGQSQNTGYGTQSTPQGYGSTGGYGSSQSSQSSYGQQSSYPGYGQQPAPSSTSGSYGSSSQSSSYGQPQSGSYSQQPSYGGQQQSYGQQQSYNPPQGYGQQNQYNS'
regex = ((?:(?!GYG)[^Y]){1,3})?GYG((?:(?!GYG)[^Y]){1,3})?
for matchedobj in re.finditer(regex, seq):
    ls.append(matchedobj.group(1)) # gives the matches preceeding GYG
    ls.append(matchedobj.group(2)) # gives matches that follow GYG

0
投票

代替使用* SKIP * FAIL,您可以使用带有环视效果的替代方法。

如果要在匹配GYG之前或之后匹配n个字符,但是如果在GYG和n之间的范围内遇到Y,则返回两者之间匹配的字符,则可以使用与除YG之外的任何单词char匹配的否定字符类。

仅在不被左侧的GY或右侧的YG包围时匹配G。

(?:(?:[^\WYG]|G(?<!GYG)(?!YG)){1,3}+(?=GYG)|(?<=GYG)(?:[^\WYG]|G(?<!GYG)(?!YG)){1,3}+)

Regex demo

说明

  • (?:非捕获组
    • (?:非捕获组
      • [[^\WYG]匹配除Y或G以外的任何字符char
      • |
      • [G(?<!GYG)(?!YG)匹配G时不要在GYG之前或之后是YG
    • [){1,4}+关闭组并使用所有格修饰符重复1-4次
    • (?=GYG)正向前进,断言右边是GYG
    • |
    • (?<=GYG)向后看,断言左边是GYG
    • (?:非捕获组
      • [[^\WYG]匹配除Y或G以外的任何字符char
      • |
      • [G(?<!GYG)(?!YG)匹配G时不要在GYG之前或之后是YG
    • [){1,4}+关闭组并使用所有格修饰符重复1-4次
  • [)关闭组
© www.soinside.com 2019 - 2024. All rights reserved.