2013-04-02 196 views
5

在我的節目,我有一個這樣的字符串:只使用Python保持字符串中的某些字符?

AG CT OSO gcota

使用Python,我的目標是擺脫白色空間,只保留A,T,C和G字。 我明白如何擺脫空白(我只是使用line = line.replace(「」,「」))。但是我怎樣才能擺脫我不需要的字符,當他們可以是字母表中的任何其他字母?

回答

12

一個非常優雅和快速的方法是使用正則表達式:

import re 

str = 'ag ct oso gcota' 
str = re.sub('[^atcg]', '', str) 

"""str is now 'agctgcta""" 
+0

你贏了:)(+1)。我不知道爲什麼我沒有想到這個'正則表達式'... – mgilson

+0

我也給你+1了。你提供的第二個解決方案(str.translate)對我來說是新的:) –

4

我可能會做這樣的事情:

chars_i_want = set('atcg') 
final_string = ''.join(c for c in start_string if c in chars_i_want) 

這可能是最簡單的方式。


另一種選擇是使用str.translate做的工作:

import string 
chars_to_remove = string.printable.translate(None,'acgt') 
final_string = start_string.translate(None,chars_to_remove) 

我不知道這將有更好的表現。它需要通過timeit定時來確定地知道。


更新:計時!

import re 
import string 

def test_re(s,regex=re.compile('[^atgc]')): 
    return regex.sub(s,'') 

def test_join1(s,chars_keep=set('atgc')): 
    return ''.join(c for c in s if c in chars_keep) 

def test_join2(s,chars_keep=set('atgc')): 
    """ list-comp is faster, but less 'idiomatic' """ 
    return ''.join([c for c in s if c in chars_keep]) 

def translate(s,chars_to_remove = string.printable.translate(None,'acgt')): 
    return s.translate(None,chars_to_remove) 

import timeit 

s = 'ag ct oso gcota' 
for func in "test_re","test_join1","test_join2","translate": 
    print func,timeit.timeit('{0}(s)'.format(func),'from __main__ import s,{0}'.format(func)) 

可悲的是(對我來說),regex勝我的機器上:

test_re 0.901512145996 
test_join1 6.00346088409 
test_join2 3.66561293602 
translate 1.0741918087 
+0

regex.sub()的用法不正確,因此計時錯誤。它應該是regex.sub('',s)而不是其他方式。 –

0

有沒有人測試mgilson的test_re ()函數在upvoting之前? re.sub()的參數是相反的,所以它是在空字符串中進行替換,並且總是返回空字符串。

我在Python 3.4中工作; string.translate()只需要一個參數,一個字典。由於在構建這個詞典時有開銷,我將它移出了該函數。公平地說,我也將正則表達式編譯從函數中移出(這並沒有引起明顯的區別)。

import re 
import string 

regex=re.compile('[^atgc]') 

chars_to_remove = string.printable.translate({ ord('a'): None, ord('c'): None, ord('g'): None, ord('t'): None }) 
cmap = {} 
for c in chars_to_remove: 
    cmap[ord(c)] = None 

def test_re(s): 
    return regex.sub('',s) 

def test_join1(s,chars_keep=set('atgc')): 
    return ''.join(c for c in s if c in chars_keep) 

def test_join2(s,chars_keep=set('atgc')): 
    """ list-comp is faster, but less 'idiomatic' """ 
    return ''.join([c for c in s if c in chars_keep]) 

def translate(s): 
    return s.translate(cmap) 

import timeit 

s = 'ag ct oso gcota' 
for func in "test_re","test_join1","test_join2","translate": 
    print(func,timeit.timeit('{0}(s)'.format(func),'from __main__ import s,{0}'.format(func))) 

這裏是計時:

test_re 3.3141989699797705 
test_join1 2.4452173250028864 
test_join2 2.081048655003542 
translate 1.9390292020107154 

這太糟糕了string.translate()沒有一個選項來控制如何處理不在地圖上的字符做。目前的實現是保留它們,但是如果我們想要保留的角色遠遠少於我們想要移除的角色(哦,你好,unicode),我們也可以選擇刪除它們。