使用 Python 正则表达式在模式内剪切

Cut within a pattern using Python regex

Objective: 我正在尝试在 Python RegEx 中进行切割,其中拆分并不完全符合我的要求。我需要在模式内剪切,但在字符之间剪切。

我要找的是:

我需要在字符串中识别下面的模式,并在管道的位置拆分字符串。管道实际上并不在字符串中,它只是显示我要拆分的位置。

模式:CDE|FG

字符串:ABCDEFGHIJKLMNOCDEFGZYPE

结果:['ABCDE', 'FGHIJKLMNOCDE', 'FGZYPE']

我试过的:

我似乎使用带括号的拆分很接近,但它并没有像我需要的那样将搜索模式附加到结果。

re.split('CDE()FG', 'ABCDEFGHIJKLMNOCDEFGZYPE')

给予,

['AB', 'HIJKLMNO', 'ZYPE']

当我真正需要的时候,

['ABCDE', 'FGHIJKLMNOCDE', 'FGZYPE']

动机:

正在练习 RegEx,想看看我是否可以使用 RegEx 制作一个脚本来预测使用特定蛋白酶消化蛋白质的片段。

你可以用re.split()和积极的"look arounds"解决它:

>>> re.split(r"(?<=CDE)(\w+)(?=FG)", s)
['ABCDE', 'FGHIJKLMNOCDE', 'FGZYPE']

请注意,如果其中一个剪切序列是空字符串,您将在结果列表中得到一个空字符串。你可以处理 "manually",示例(我承认,它不是那么漂亮):

import re

s = "ABCDEFGHIJKLMNOCDEFGZYPE"

cut_sequences = [
    ["CDE", "FG"],
    ["FGHI", ""],
    ["", "FGHI"]
]

for left, right in cut_sequences:
    items = re.split(r"(?<={left})(\w+)(?={right})".format(left=left, right=right), s)

    if not left:
        items = items[1:]

    if not right:
        items = items[:-1]

    print(items)

打印:

['ABCDE', 'FGHIJKLMNOCDE', 'FGZYPE']
['ABCDEFGHI', 'JKLMNOCDEFGZYPE']
['ABCDE', 'FGHIJKLMNOCDEFGZYPE']

一种非正则表达式的方式是 replace the pattern with the piped value and then split

>>> pattern = 'CDE|FG'
>>> s = 'ABCDEFGHIJKLMNOCDEFGZYPE'
>>> s.replace('CDEFG',pattern).split('|')
['ABCDE', 'FGHIJKLMNOCDE', 'FGZYPE']

一个更安全的非正则表达式解决方案可能是这样的:

import re

def split(string, pattern):
    """Split the given string in the place indicated by a pipe (|) in the pattern"""
    safe_splitter = "#@#@SPLIT_HERE@#@#"
    safe_pattern = pattern.replace("|", safe_splitter)
    string = string.replace(pattern.replace("|", ""), safe_pattern)
    return string.split(safe_splitter)

s = "ABCDEFGHIJKLMNOCDEFGZYPE"
print(split(s, "CDE|FG"))
print(split(s, "|FG"))
print(split(s, "FGH|"))

https://repl.it/C448

要在使用 re.split 或其中的一部分拆分时保持拆分模式,请将它们括在括号中。

>>> data
'ABCDEFGHIJKLMNOCDEFGZYPE'
>>> pieces = re.split(r"(CDE)(FG)", data)
>>> pieces
['AB', 'CDE', 'FG', 'HIJKLMNO', 'CDE', 'FG', 'ZYPE']

很简单。所有零件都在那里,但正如您所见,它们已被分开。所以我们需要重新组装它们。那是比较棘手的部分。仔细观察,您会发现您需要将前两块、后两块和其余三块拼接起来。我通过填充列表来简化代码,但如果性能有问题,您可以使用原始列表(和一些额外的代码)来完成。

>>> pieces = [""] + pieces
>>> [ "".join(pieces[i:i+3]) for i in range(0,len(pieces), 3) ]
['ABCDE', 'FGHIJKLMNOCDE', 'FGZYPE']

re.split() 保证每个捕获(带括号的)组都有一块,加上介于两者之间的一块。对于需要自己分组的更复杂的正则表达式,使用非捕获组来保持返回数据的格式相同。 (否则您需要调整重组步骤。)

PS。我也喜欢 Bhargav Rao 关于在字符串中插入分隔符的建议。如果性能不是问题,我想这是一个品味问题。

编辑:这是一种(不太透明的)方法,无需向列表中添加空字符串:

pieces = re.split(r"(CDE)(FG)", data)
result = [ "".join(pieces[max(i-3,0):i]) for i in range(2,len(pieces)+2, 3) ]