Python 计算正则表达式的每个部分匹配的内容
我有几百个(相当简单的)正则表达式以及它们在大量序列中的匹配项。我想知道每个正则表达式的哪个部分匹配目标序列中的哪个位置。例如,以下正则表达式“[DSTE][^P][^DEWHFYC]D[GSAN]”可以按以下顺序与位置4到8匹配: ABCSGADAZZZ 我想(通过编程)得到的是,对于每个正则表达式,1)正则表达式的每个“部分”,2)目标序列中与其匹配的位置:Python 计算正则表达式的每个部分匹配的内容,python,regex,grammar,text-parsing,Python,Regex,Grammar,Text Parsing,我有几百个(相当简单的)正则表达式以及它们在大量序列中的匹配项。我想知道每个正则表达式的哪个部分匹配目标序列中的哪个位置。例如,以下正则表达式“[DSTE][^P][^DEWHFYC]D[GSAN]”可以按以下顺序与位置4到8匹配: ABCSGADAZZZ 我想(通过编程)得到的是,对于每个正则表达式,1)正则表达式的每个“部分”,2)目标序列中与其匹配的位置: [DSTE] -- (3, 4), [^P] -- (4, 5), [^DEWHFYC] -- (5, 6), D -- (6, 7)
[DSTE] -- (3, 4),
[^P] -- (4, 5),
[^DEWHFYC] -- (5, 6),
D -- (6, 7),
[GSAN] -- (7, 8)
我找到了这个网站,它基本上实现了我想要的功能:,但我不确定我需要深入到正则表达式解析的多深才能在我自己的代码中实现这一点(我使用的是Python和R)。如果你想提取正则表达式每个部分匹配的字符串位置,那么你应该用()
将每一块制作成一个捕获组。如果不这样做,您将无法分析正则表达式每个部分匹配的位置
([DSTE])([^P])([^DEWHFYC])(D)([GSAN])
现在,您可以看到每个部分都是分开的。因此,可以使用另一个正则表达式提取正则表达式的每个部分
\((.*?)(?=\)(?:\(|$))
奖励:您还可以提取与正则表达式的每个部分匹配的文本部分
([DSTE])([^P])([^DEWHFYC])(D)([GSAN])
所以,使用方法获得所需的数据,如下所示
import re
text = 'ABCSGADAZZZ'
theRegex = r'([DSTE])([^P])([^DEWHFYC])(D)([GSAN])'
r1 = re.compile(r'\((.*?)(?=\)(?:\(|$))') # each part extractor
r2 = re.compile(theRegex) # your regex
grps = r1.findall(theRegex) # parts of regex
m = re.search(r2, text)
for i in range(len(grps)):
print( 'Regex: {} | Match: {} | Range: {}'.format(grps[i], m.group(i+1), m.span(i+1)) )
我从未见过一个具有此类功能的正则表达式引擎在其API中公开。或者还没有意识到这样的API。可能有一个,但在R或Python中不是必需的 但无论如何,这并不像我想象的那么简单 考虑regex
/(a(b*)*/
over“abbabb”
,b*
部分匹配的不仅仅是一个子字符串。相反,可以有一个子串,它与某个正则表达式的多个部分匹配
即使你的正则表达式“相当简单”。。。它们是否都像问题中的那样简单
正如其他人已经提到的,您可以使用捕获组来找出哪个组匹配什么,但为此,您需要自己编辑正则表达式并跟踪组的索引。或者,是的,编写您自己的解析器。因为正则表达式不能解析正则表达式——它们对于自己的语法来说不够强大
…嗯,如果你的正则表达式真的很简单,而且或多或少是一致的,那么也许有一种方法可以自动、轻松地解析和修改它们(添加捕获组)。但是考虑到你的正则表达式只有一个例子,这是不可能的
…但你可能问错了问题:
许多海报陷入的一个陷阱是问如何实现一些“小”目标,但永远不要说更大的目标是什么。通常,较小的目标要么不可能,要么很少是个好主意——相反,需要一种不同的方法
更新:
我对示例字符串和正则表达式做了一些修改,以解释您在注释中提到的p{1,3}
情况
下面是修改regex
es并获得所需输出的代码:
重新导入
orig_re=“[DSTE]{1,1}[^P][^DEWHFYC]DP{1,3}[GSAN]”
mod_re=r'(\[.*.]\.)(\{.*.\})'
组=re.findall(mod\u re,orig\u re)
打印(“regex的部分:,[g[0]表示g在组中])
new_regex_str=re.sub(mod_re,r'(\1'),orig_re)
打印(“带捕获组的新正则表达式:”,新正则表达式)
new_re=re.compile(new_regex_str)
str=“abcsgadpappazzsgadpa”
matches=新的查找器(str)
对于匹配中的m:
打印('------------')
对于范围内的g(len(组)):
打印('{}:{}--{}'。格式(g,groups[g][0],m.span(g+1)))
它会给你:
parts of regex: ['[DSTE]{1,1}', '[^P]', '[^DEWHFYC]', 'D', 'P{1,3}', '[GSAN]']
new regex with capturing groups: ([DSTE]{1,1})([^P])([^DEWHFYC])(D)(P{1,3})([GSAN])
----------
#0: [DSTE]{1,1} -- (3, 4)
#1: [^P] -- (4, 5)
#2: [^DEWHFYC] -- (5, 6)
#3: D -- (6, 7)
#4: P{1,3} -- (7, 9)
#5: [GSAN] -- (9, 10)
----------
#0: [DSTE]{1,1} -- (13, 14)
#1: [^P] -- (14, 15)
#2: [^DEWHFYC] -- (15, 16)
#3: D -- (16, 17)
#4: P{1,3} -- (17, 18)
#5: [GSAN] -- (18, 19)
也在JS中
const orig_re=“[DSTE]{1,1}[^P][^DEWHFYC]DP{1,3}[GSAN]”
常量mod_re=/(\[.*.\]|.)(\{.*.\})/g
groups=[…原始匹配(mod_re)].map(g=>g[0])
log(“regex的部分:”,组)
const new_re=原始替换(mod_re,“($1)”)
log(“带有捕获组的新正则表达式:”,new\u re)
const str=“abcsgadpappazzsgadpa”
matches=str.matchAll(新的)
for(匹配常数m){
console.log('------------')
设pos=m.index
groups.forEach((g,i)=>console.log(`${i}:${g}--(${pos},${pos+=m[i+1].length})`))
}
使用该软件包,您应该能够这样组合:
> stringr::str_match_all(string = "ABCSGADAZZZ",
pattern = "[DSTE][^P][^DEWHFYC]D[GSAN]")
[[1]]
[,1]
[1,] "SGADA"
> stringr::str_locate_all(string = "ABCSGADAZZZ",
pattern = "[DSTE][^P][^DEWHFYC]D[GSAN]")
[[1]]
start end
[1,] 4 8
然后组合函数输出或编写一个简单的包装函数,虽然还不是100%,但我在数据集的3365/3510上返回了输出。我检查过的几个人排成一行:) 我的github(链接如下)中包含csv、txt(分别)格式的输入和输出 请忽略全局变量;我正在考虑转换代码,看看速度是否有明显的提高,但没有回避 当前,此版本在有关交替和开始/结束行运算符(^$)的操作顺序方面存在问题,如果它们是字符串开头或结尾处的交替选项。我很有信心这与先例有关;但我没能把它组织得足够好 代码的函数调用位于最后一个单元格中。而不是使用
for x in range(len(df)):
try:
df_expression = df.iloc[x, 2]
df_subsequence = df.iloc[x, 1]
# call function
identify_submatches(df_expression, df_subsequence)
print(dataframe_counting)
dataframe_counting += 1
except:
pass
通过向函数传递模式和相应的序列,您可以轻松地一次测试一个,如下所示:
p = ''
s = ''
identify_submatches(p, s)
代码:
投入:
产出:
数据来源:
ELM(蛋白质功能位点的真核线性基序资源)2020。从中检索,用更简单的正则表达式(例如,
\b[a-Z]+\b
)匹配文本中的整个序列,然后在找到的字符串上使用您的表达式。“部分”是否始终只匹配一个字符?如果不是,你怎么知道什么是“部分”?我想它们应该是单个字符,除非它们重复或明确分组,但我不确定这是否涵盖了所有可能的场景(也不确定我链接的网站如何分解每个正则表达式)。这真的取决于你决定如何分割匹配。对于你的问题中的模式
Expression Input: [KR]{1,4}[KR].[KR]W.
Sequence Input: TRQARRNRRRRWRERQRQIH
Subequence Match: RRRRWR
[KR]{1} (7, 8)
[KR] (8, 9)
. (9, 10)
[KR] (10, 11)
W (11, 12)
. (12, 13)
2270
Expression Input: [KR]{1,4}[KR].[KR]W.
Sequence Input: TASQRRNRRRRWKRRGLQIL
Subequence Match: RRRRWK
[KR]{1} (7, 8)
[KR] (8, 9)
. (9, 10)
[KR] (10, 11)
W (11, 12)
. (12, 13)
2271
Expression Input: [KR]{1,4}[KR].[KR]W.
Sequence Input: TRKARRNRRRRWRARQKQIS
Subequence Match: RRRRWR
[KR]{1} (7, 8)
[KR] (8, 9)
. (9, 10)
[KR] (10, 11)
W (11, 12)
. (12, 13)
2272
Expression Input: [KR]{1,4}[KR].[KR]W.
Sequence Input: LDFPSKKRKRSRWNQDTMEQ
Subequence Match: KKRKRSRWN
[KR]{4} (5, 9)
[KR] (9, 10)
. (10, 11)
[KR] (11, 12)
W (12, 13)
. (13, 14)
2273
Expression Input: [KR]{1,4}[KR].[KR]W.
Sequence Input: ASQPPSKRKRRWDQTADQTP
Subequence Match: KRKRRWD
[KR]{2} (6, 8)
[KR] (8, 9)
. (9, 10)
[KR] (10, 11)
W (11, 12)
. (12, 13)
2274
Expression Input: [KR]{1,4}[KR].[KR]W.
Sequence Input: GGATSSARKNRWDETPKTER
Subequence Match: RKNRWD
[KR]{1} (7, 8)
[KR] (8, 9)
. (9, 10)
[KR] (10, 11)
W (11, 12)
. (12, 13)
2275
Expression Input: [KR]{1,4}[KR].[KR]W.
Sequence Input: PTPGASKRKSRWDETPASQM
Subequence Match: KRKSRWD
[KR]{2} (6, 8)
[KR] (8, 9)
. (9, 10)
[KR] (10, 11)
W (11, 12)
. (12, 13)
2276
Expression Input: [VMILF][MILVFYHPA][^P][TASKHCV][AVSC][^P][^P][ILVMT][^P][^P][^P][LMTVI][^P][^P][LMVCT][ILVMCA][^P][^P][AIVLMTC]
Sequence Input: LLNAATALSGSMQYLLNYVN
Subequence Match: LLNAATALSGSMQYLLNYV
[VMILF] (0, 1)
[MILVFYHPA] (1, 2)
[^P] (2, 3)
[TASKHCV] (3, 4)
[AVSC] (4, 5)
[^P] (5, 6)
[^P] (6, 7)
[ILVMT] (7, 8)
[^P] (8, 9)
[^P] (9, 10)
[^P] (10, 11)
[LMTVI] (11, 12)
[^P] (12, 13)
[^P] (13, 14)
[LMVCT] (14, 15)
[ILVMCA] (15, 16)
[^P] (16, 17)
[^P] (17, 18)
[AIVLMTC] (18, 19)
2277
Expression Input: [VMILF][MILVFYHPA][^P][TASKHCV][AVSC][^P][^P][ILVMT][^P][^P][^P][LMTVI][^P][^P][LMVCT][ILVMCA][^P][^P][AIVLMTC]
Sequence Input: IFEASKKVTNSLSNLISLIG
Subequence Match: IFEASKKVTNSLSNLISLI
[VMILF] (0, 1)
[MILVFYHPA] (1, 2)
[^P] (2, 3)
[TASKHCV] (3, 4)
[AVSC] (4, 5)
[^P] (5, 6)
[^P] (6, 7)
[ILVMT] (7, 8)
[^P] (8, 9)
[^P] (9, 10)
[^P] (10, 11)
[LMTVI] (11, 12)
[^P] (12, 13)
[^P] (13, 14)
[LMVCT] (14, 15)
[ILVMCA] (15, 16)
[^P] (16, 17)
[^P] (17, 18)
[AIVLMTC] (18, 19)
2278
Expression Input: [VMILF][MILVFYHPA][^P][TASKHCV][AVSC][^P][^P][ILVMT][^P][^P][^P][LMTVI][^P][^P][LMVCT][ILVMCA][^P][^P][AIVLMTC]
Sequence Input: IYEKAKEVSSALSKVLSKID
Subequence Match: IYEKAKEVSSALSKVLSKI
[VMILF] (0, 1)
[MILVFYHPA] (1, 2)
[^P] (2, 3)
[TASKHCV] (3, 4)
[AVSC] (4, 5)
[^P] (5, 6)
[^P] (6, 7)
[ILVMT] (7, 8)
[^P] (8, 9)
[^P] (9, 10)
[^P] (10, 11)
[LMTVI] (11, 12)
[^P] (12, 13)
[^P] (13, 14)
[LMVCT] (14, 15)
[ILVMCA] (15, 16)
[^P] (16, 17)
[^P] (17, 18)
[AIVLMTC] (18, 19)
2279
Expression Input: [VMILF][MILVFYHPA][^P][TASKHCV][AVSC][^P][^P][ILVMT][^P][^P][^P][LMTVI][^P][^P][LMVCT][ILVMCA][^P][^P][AIVLMTC]
Sequence Input: IYKAAKDVTTSLSKVLKNIN
Subequence Match: IYKAAKDVTTSLSKVLKNI
[VMILF] (0, 1)
[MILVFYHPA] (1, 2)
[^P] (2, 3)
[TASKHCV] (3, 4)
[AVSC] (4, 5)
[^P] (5, 6)
[^P] (6, 7)
[ILVMT] (7, 8)
[^P] (8, 9)
[^P] (9, 10)
[^P] (10, 11)
[LMTVI] (11, 12)
[^P] (12, 13)
[^P] (13, 14)
[LMVCT] (14, 15)
[ILVMCA] (15, 16)
[^P] (16, 17)
[^P] (17, 18)
[AIVLMTC] (18, 19)
2280