2015-12-04 23 views
0

從我的搜索中,我看到這種問題已被多次詢問,並且我理解了規範化的解決方案。但是,沒有解決我遇到的具體問題。我試圖編寫一個函數,用Python 3.4中的RegEx去除字符串中的無意義字符(來自任何數量的不同類型的生物信息學文件的染色體ID)。關於什麼樣的奇怪字符可能存在沒有一般的規則,所以想法是這樣寫的,以便可以快速添加新的特殊情況,並且我在下面的代碼中包含了一些例子。空白和^不工作 - 在Python 3中多次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」,但 不是「CHROMOSOME12」是儘管re.IGNORECASE替換爲「12」)
  2. 代一個字符串的開頭不起作用('chr12'不是 被'12'取代)。
  3. 空白字符不會被刪除,例如\ s,儘管它們是作爲原始字符串包含的 。

沒有例子我已經能夠找到使用字典鍵和值的方式,以這種方式查看這些特殊字符的行爲。

不過,如果我寫的東西,如:

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

這工作得很好,用一個零替換零任意數量的字符串。

那麼上述代碼的問題是什麼?如果你真的好好看一看。我可以爲每個特定的實例鍵入re.sub(),但肯定有更高效的方法來實現此目的。

回答

0

根據kindall的建議,我簡化了一些東西。 Lambdas有時很方便,但在這種情況下不是必需的,它使得事情變得不可讀。有序的字典是一個不錯的主意,但沒有必要。

解決方案:

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不前工作,但現在一切都很好。

2

您用來構建OrderedDict的2元組的普通列表可能是更好的數據結構,因爲模式與其替換之間不存在真正的鍵/值關係。此外,你有一個重複的密鑰,這將只出現在字典中一次!將它作爲列表將使用更少的內存來啓動(儘管可能不是主要因素)。

我看到的主要問題是您正在以編程方式轉義您的模式。因此,模式中的特殊字符沒有特殊含義。例如,+re.escape()更改爲\+,這意味着它現在匹配文字加號,而不是「前面的一個或多個字符」。這並不能解釋您的一些問題(例如,不區分大小寫無法正常工作),但是在解決此問題之前,您會對所有問題感到困惑。

什麼你應該做的,而不是爲逃避需要在原來的模式逃避的東西(例如,我想在如li|旨在匹配一個|的圖案|角色,所以應該寫成\|)並且不要使用re.escape()

此外,由於您沒有對替換做任何事情,所以您可以在調用中使用替換文本的re.sub(),而不是編寫lambda來做同樣的事情。

+0

其中一個小建議變得非常有價值! 我正在使這個更復雜,可讀性更差,因此比我用分類字典所需的「pythonic」更少。我仍然不完全明白所有問題是什麼,但是現在通過消除這個問題和程序化轉義來解決問題。非常感謝。 – Jeff