在我只有一个字母的字符串中,我试图找到某个图案GYG
的相邻字符,并达到一定深度dep
。但是,如果在达到所需深度之前找到字符Y
,则正则表达式引擎应中断并返回在GYG
和Y
之间找到的所有字符。
以说明:
dep = 2
中的XXXGYGXXXYXGYGXX
,所需的匹配为XX
XX
X
XX
dep = 3
中的XXXGYGXXXYXGYGXX
,所需的匹配为XXX
XXX
X
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']
[这里的挑战是,取反的模式GYG
是对称的,它在两侧G
上均包含Y
字符。因此,出于各种原因,积极的环顾四周行不通。
有两种方法可以解决这个问题。首先,是使用环顾四周。
第一种方法:环顾四周方法
要设置关于GYG
主题的环顾四周,但仍捕获独立的G
字符,我们首先取反all G
字符。由于Y
字符也不应该被捕获,因此我们将G
和Y
都放在否定的类[^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
代替使用* 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}+)
说明
(?:
非捕获组(?:
非捕获组[^\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次)
关闭组