空格和 ^ 不工作 - Python 3 中的多个 RegEx 替换

Whitespace and ^ Not Working - Multiple RegEx Substitution in Python 3

根据我的搜索,我发现此类问题已被多次询问,并且我了解规范的解决方案。但是,none 解决了我遇到的具体问题。我正在尝试编写一个函数,以在 Python 3.4(来自我正在处理的任何数量的不同类型的生物信息学文件的染色体 ID)中使用 RegEx 去除字符串中的无意义字符。对于可能出现的奇怪字符类型没有一般规则,所以我的想法是以这样一种方式编写它,以便可以快速添加新的特殊情况,我在下面的代码中包含了一些示例。

遵循其他几个帖子的逻辑:

How can I do multiple substitutions using regex in python?

Efficiently carry out multiple string replacements in Python

multiple regex substitution in multiple files using python

Multiple, specific, regex substitutions in Python

Python replace multiple strings

等...

我写了以下内容:

def fix_chromosome_id(chromosome):
    replacements = OrderedDict([(r'lcl|', ''),
                                (r'gi|', ''),
                                (r'chromosome', ''),
                                (r'^chr', ''),
                                (r'_+', ''),
                                (r'\s+', ''),
                                (r'^\s', ''),
                                (r'\s$', ''),
                                (r'/', '_'),
                                (r'|$', ''),
                                (r'|', '_'),
                                (r'(', '_'),
                                (r')', '_'),
                                (r'_+', '_')])  # Ordered dictionary of regex and substitutions from list of tuples

    # Compile as regex objects, substitute regex as specified in the ordered dictionary
    pattern = re.compile('|'.join(re.escape(regex) for regex in replacements))
    chromosome = pattern.sub(lambda match: replacements[match.group(0)], chromosome, re.IGNORECASE)

您可以看到我已经从元组列表创建了一个有序字典,因为替换的顺序很重要,而标准字典不会处理这个问题。然后使用这些键作为 RegEx 并尝试用它们对应的值替换。

我的问题:

  1. 不区分大小写替换不起作用('chromosome12' 但 尽管 re.IGNORECASE)
  2. 不是 'CHROMOSOME12' 被替换为 '12'
  3. 替换字符串的开头不起作用('chr12' 不是 替换为“12”)。
  4. 没有删除空白字符,例如 \s,尽管它们是 作为原始字符串包含在内。

我找不到任何使用字典键和值的示例以这种方式查看这些特殊字符的行为。

但是,如果我这样写:

if re.search(r'^0+$', chromosome):
        chromosome = 0

这对于用一个零替换一串由任意数量的零组成的字符串来说效果很好。

那么上面的代码有什么问题呢?如果你愿意看一看。我可以为每个特定实例键入 re.sub(),但肯定有更有效的方法来执行此操作。

你用来构建 OrderedDict 的二元组的简单列表可能是一个更好的数据结构,因为模式和之间没有真正的 key/value 关系它的替代品。此外,您有一个重复的键,并且它只会在字典中出现一次!将其保留为列表将使用更少的内存来启动(不过可能不是主要因素)。

我看到的主要问题是您正在以编程方式转义您的模式。因此,您的模式中的特殊字符没有它们的特殊含义。例如,+re.escape() 更改为 \+ 这意味着它现在匹配文字加号,而不是 "one or more of the preceding character." 这并不能解释你的一些问题(例如不区分大小写不起作用),但在解决此问题之前,您会对所有事情感到非常困惑。

您可能应该做的是转义原始模式中需要转义的内容(例如,我假设 li| 等模式中的 | 字符旨在匹配文字 |,所以应该写成 \|) 而不要使用 re.escape().

此外,由于您没有对替换做任何花哨的事情,您可以直接在调用中将 re.sub() 与替换文本一起使用,而不是写一个 lambda 来做同样的事情.

根据 kindall 的建议,我稍微简化了一些事情。 Lambda 有时很方便,但在这种情况下不是必需的,它会降低可读性。有序字典是个好主意,但没必要。

解决方案:

def fix_chromosome_id(chromosome):
        replacements = [('lcl\|', ''),
                        ('gi\|', ''),
                        ('chromosome', ''),
                        ('^chr', ''),
                        ('^_+', ''),
                        ('\s+', ''),
                        ('^\s', ''),
                        ('\s$', ''),
                        ('\/', '_'),
                        ('\|$', ''),
                        ('\|', '_'),
                        ('\(', '_'),
                        ('\)', '_'),
                        ('_+', '')]  # Regex and substitutions from list of tuples

        # Compile as regex objects, substitute regex as specified in the ordered dictionary
        for rep_tuple in replacements:
            regex_pattern = re.compile(rep_tuple[0], re.IGNORECASE)
            rep = rep_tuple[1]
            chromosome = regex_pattern.sub(rep, chromosome)

不知道为什么 re.IGNORECASE 以前不工作,但现在一切正常。