1. 什是正則表達(dá)式说庭?
答:正則表達(dá)式又稱規(guī)則表達(dá)式,英語是Regular Expression郑趁,在代碼中常簡寫為regex刊驴、regexp或RE,這計算機(jī)科學(xué)的一個概念寡润。正則表達(dá)式通常被用來檢索捆憎、替換那些符合某個模式(規(guī)則)的文本。 許多程序設(shè)計語言都支持利用正則表達(dá)式進(jìn)行字符串操作悦穿。正則表達(dá)式包括普通字符(例如攻礼,a 到 z 之間的字母)和特殊字符(稱為"元字符")。正則表達(dá)式使用單個字符串來描述栗柒、匹配一系列匹配某個句法規(guī)則的字符串礁扮。它的使用類似于通配符(wildchars)知举,例如在Linux的命令行中輸入ls *.py
就會列出所有以".py"結(jié)尾的文件。
有時候我們要處理一些字符串太伊,例如雇锡,我要提取一些位于<pre>
和</pre>
之間的廣西,或者是從一個文件中清除一些非ATCG的字符僚焦,都要用到正則表達(dá)式锰提。
2. 正則表達(dá)式在生物學(xué)方面有什么用處?
答:正則表達(dá)式的這種特征在生物學(xué)方面使用極為,廣泛,利用正則表達(dá)式芳悲,可以很好地定位蛋白質(zhì)的結(jié)構(gòu)域立肘,DNA的一些序列模式,例如CpG島名扛,重復(fù)序列谅年,限制性內(nèi)切酶位點,核酸識別位點肮韧。
3. 不同編程語言之間的正則表達(dá)式相同不融蹂?
答:許多編程語言都支持正則表達(dá)式,每種編程語言都有自己的正則表達(dá)式語法弄企,不過大體上是相同的超燃。Python的正則表達(dá)式與Perl接近,如果會使用Perl拘领,那么Python的正則表達(dá)式學(xué)起來也非常容易意乓。
4. 正則表達(dá)式是按照哪些規(guī)則來匹配文本的?
答:在Python中院究,通常情況下洽瞬,字母與單詞匹配他們本身,例如“Python”就匹配“Python"业汰,而不是"python"伙窃,還有一些特殊的字符用于特殊的匹配,以. ^ $ * + ? { [ ] \ | ( )
為例說明一下样漆,如下表所示:
.
號:匹配除除換行符 \n 之外的任何字符为障,例如“ATT.T”會匹配“ATTCT”,"ATTFT"放祟,但不會匹配“ATTTCT”鳍怨。^
(克拉符號):匹配輸入字符串的開始位置,例如“AUG”會匹配“AUGAGC”跪妥,但不匹配“AAUGC”鞋喇。如果是在方括號里使用,例如[^AUG]表示相反的意思眉撵,即不匹配以AUG開頭的字符串侦香。$
(美元符號):在一行字符串中落塑,匹配輸入字符串的結(jié)尾位置谱醇,例如“UAA$”匹配“AGCUAA”资盅,但不匹配“ACUAAG”颜曾。*
(星號):匹配前面的子表達(dá)式零次或多次重復(fù)岭粤。例如“AT*”會匹配“AAT”,“A”十籍,但不匹配“TT”箱硕。+
(加號):匹配前面的子表達(dá)式一次或多次重復(fù)期揪》溃“AT+”會匹配“ATT”晦款,但不匹配“A”。?
匹配前面的子表達(dá)式零次或一次重復(fù)顷锰,“AT?”會匹配“A”或“AT”柬赐。(...)
(括號):匹配圓括號中的表達(dá)式,用于表明匹配的開始與結(jié)構(gòu)官紫,如果只匹配括號,例如匹配“(”或“)”時州藕,可以使用(或)束世,或者是將它們放到中括號里[(][)]。(?:...)
:匹配但不捕獲該匹配的子表達(dá)式床玻。{n}
:n是一個非負(fù)整數(shù)毁涉,匹配重復(fù)的某字符串的n次。例如锈死,“(ATTG){3}”匹配ATTGATTGATTG贫堰,但是不匹配“ATTGATTG”。(第1個是重復(fù)了3次待牵,第2個是重復(fù)了2次)其屏。{m,n}
:m和n均為非負(fù)整數(shù),其中m<=n缨该,它表示最少匹配n次且最多匹配m次偎行。例如“(AT){3,5}”會匹配“ATATTATATAT”,但是不匹配“ATATTATAT”贰拿,如果不加m蛤袒,則是從匹配0次的開始,如果沒有n膨更,則匹配任意重復(fù)的某字符串妙真。[]
:表示一組字符串〖允兀“[A-Z]”會匹配任何大寫的字母珍德,而“[a-z0-9]”則會匹配任何小寫的字母以及數(shù)字练般。“[AT]”匹配“A”菱阵,“T”踢俄,或“(星號)”。在中括號里晴及,^
表示相反的含義都办,例如“[^R]”會匹配任何除了“R”之外的字母。\
:將下一個字符標(biāo)記為或特殊字符虑稼、或原義字符琳钉、或向后引用、或八進(jìn)制轉(zhuǎn)義符蛛倦。例如歌懒, 'n' 匹配字符 'n'。'\n' 匹配換行符溯壶。序列 '\' 匹配 ""及皂,而 '(' 則匹配 "("。-
|
:表達(dá)“或”的意思且改,指明兩項之間的一個選擇验烧,例如“A|T”會匹配“A”,“T”或“AT”又跛。
Python中的一些特殊字符總結(jié)如下所示:
元字符 功能說明 () 將位于()中的內(nèi)容作為一個整體來對待 {} 按{}中的次數(shù)進(jìn)行匹配 [] 匹配位于[]中的任意一個字符 [^xyz] ^放在[]內(nèi)表示反向字符集碍拆,匹配除x、y慨蓝、z之外的任何字符 [a-z] 字符范圍感混,匹配指定范圍內(nèi)的任何字符 [^a-z] 反向范圍字符,匹配除小寫英文字母之外的任何字符 . 匹配除換行符以外的任意單個字符 * 匹配位于“*”之前的字符或子模式的0次或多次出現(xiàn) + 匹配位于“+”之前的字符或子模式的1次或多次出現(xiàn) - 用在[]之內(nèi)用來表示范圍 | 匹配位于“|”之前或之后的字符 ^ 匹配行首礼烈,匹配以^后面的字符開頭的字符串 $ 匹配行尾弧满,匹配以$之前的字符結(jié)束的字符串 ? 匹配位于“?”之前的0個或1個字符济丘,當(dāng)此字符緊隨任何其他限定符(*谱秽,+,?摹迷,{n}疟赊,{n,},{n,m}之后時峡碉,匹配模式是“非貪心的“近哟。“非貪心的“模式匹配搜索到的鲫寄、盡可能短的字符串吉执,而默認(rèn)的”貪心的“模式匹配搜索一的疯淫,盡可能長的字符串。例如在字符串“oooo”中戳玫,“o+?”只匹配單個o熙掺,而“o+”匹配所有o \ 表示位于\之后的為轉(zhuǎn)義字符 \num 此處的num是一個正整數(shù),例如咕宿,“(.)\1”匹配兩個連續(xù)的相同字符 \f 換頁符匹配 \n 換行符匹配 \r 匹配一個回車符 \b 匹配單詞頭或單詞尾 \B 與\b含義相反 \d 匹配任何數(shù)字币绩,相當(dāng)于[0-9] \D 代表非數(shù)字,等效于[^0-9 \s 匹配任何空白字符府阀,包括空格缆镣、制表符、換頁符试浙,與[\f\n\r\t\v]等效 \S 與\s含義相反董瞻,代表非空白字符 \w 匹配要任何字母、數(shù)字以及下畫線田巴,相當(dāng)于[a-zA-Z0-9] \W 與\w相反钠糊,與 [^A-Za-z0-9]
等效?
5. Python中有沒有正則表達(dá)式專門用的模塊?
答:在Python中壹哺,它的標(biāo)準(zhǔn)庫re
提供了正則表達(dá)式操作所需要的功能眠蚂。它的基礎(chǔ)用法如下所示,用search來說明一下斗躏,re.search()方法的功能:在給定字符串中尋找第一個匹配給定正則表達(dá)式的子字符串。
import re # 導(dǎo)入python的標(biāo)準(zhǔn)re庫
mo = re.search("hello","hello world, hello Python!")
其中search
方法的具體用法:使用公式為re.search(pattern,string,flags=0)
昔脯,其中flags的值可以是re.I(大寫的字母I啄糙,不是1),大寫表示忽略查找時的大小寫云稚,re.L(支持本地字符集的字符)隧饼,re.M(多行匹配區(qū)棲),re.S(使用元字符“.”静陈,匹配單字)燕雁。它可以在字符串內(nèi)查找模式匹配,只要找到第一個匹配鲸拥,然后就返回一個match object對象拐格,如果字符串沒有匹配,就返回None刑赶。mathch object對象有以下的方法:
group() 返回被 RE 匹配的字符串
start() 返回匹配開始的位置
end() 返回匹配結(jié)束的位置
span() 返回一個元組包含匹配 (開始,結(jié)束) 的位置
group() 返回re整體匹配的字符串捏浊,可以一次輸入多個組號,對應(yīng)組號匹配的字符串撞叨。
上述的代碼運行如下所示:
[圖片上傳失敗...(image-383245-1551584782239)]
個結(jié)果非常類似于index()方法金踪,如下所示:
"hello","hello world, hello Python!".index("hello")
('hello', 0)
不過index()與re.search()方法的不同之處在于所選用的是正則表達(dá)式浊洞,還是普通的字符串,再看一下例子:
import re
mo = re.search("[Hh]ello","Hello world, hello Python!")
mo.group()
運行結(jié)果如下所示:
mo.group()
'Hello'
其中以大寫H開頭的字符串是第一個被匹配的模式胡岔,返回法希。
6. Python中的re庫還有哪些常用的方法?
答:可以查看地一下re庫中的方法靶瘸,用命令``即可苫亦,如下所示:
impor re # 導(dǎo)入re標(biāo)準(zhǔn)庫
dir(re) # 查看re庫中所有的方法
可以看到有這些方法:
dir(re)
['A', 'ASCII', 'DEBUG', 'DOTALL', 'I', 'IGNORECASE', 'L', 'LOCALE', 'M', 'MULTILINE', 'RegexFlag', 'S', 'Scanner', 'T', 'TEMPLATE', 'U', 'UNICODE', 'VERBOSE', 'X', '_MAXCACHE', 'all', 'builtins', 'cached', 'doc', 'file', 'loader', 'name', 'package', 'spec', 'version', '_alphanum_bytes', '_alphanum_str', '_cache', '_compile', '_compile_repl', '_expand', '_locale', '_pattern_type', '_pickle', '_subx', 'compile', 'copyreg', 'enum', 'error', 'escape', 'findall', 'finditer', 'fullmatch', 'functools', 'match', 'purge', 'search', 'split', 'sre_compile', 'sre_parse', 'sub', 'subn', 'template']
常用的方法還有re.findall(),re.finditer()奕锌,re.match()著觉,
re.findall():列出字符串中模式的所有匹配項,與re.search()不同的是惊暴,re.findall()是查找所有的匹配結(jié)果饼丘,而后者只是找到第1個匹配結(jié)果,如下所示:
>>> result = re.findall("[Hh]ello","Hello world, hello Python,!")
>>> print(result)
['Hello', 'hello']
>>> print(type(result))
<class 'list'>
從上述結(jié)果可以看出辽话,re.findall()返回的結(jié)果是一個list肄鸽,而不是一個match object。
re.finditer():列出字符串中模式的所有匹配項油啤,返回一個match object典徘,這是re.finditer()與re.findall()的區(qū)別,re.finditer()返回來的是一個迭代器益咬,后者返回來的是一個list逮诲,如下所示:
>>> result = re.finditer("[Hh]ello","Hello world, hello Python,!")
>>> print(result)
<callable_iterator object at 0x00000276F7ABEC18>
>>> print(type(result))
<class 'callable_iterator'>
如果要查看結(jié)果,可以按下操作幽告,如下所示:
>>> result = re.finditer("[Hh]ello","Hello world, hello Python,!")
>>> for x in result:
... print(x.group())
... print(x.span())
...
Hello
(0, 5)
hello
(13, 18)
>>>
re.match():從字符串的開始處匹配梅鹦,返回match對象或None,它與re.search()類似冗锁,不同之處在于齐唆,re.match()只在字符串的開頭進(jìn)行匹配,而re.search()會在整個字符串中進(jìn)行匹配冻河,如下所示:
>>> result = re.match("hello","Hello world, hello Python,!")
>>> print(result)
None
如果找到了匹配結(jié)果箍邮,如下所示:
>>> result = re.match("Hello","Hello world, hello Python,!")
>>> print(result)
<_sre.SRE_Match object; span=(0, 5), match='Hello'>
可以通過group()和span()來查看匹配的結(jié)果:
>>> result = re.match("Hello","Hello world, hello Python,!")
>>> print(result)
<_sre.SRE_Match object; span=(0, 5), match='Hello'>
>>> result.group()
'Hello'
>>> result.span()
(0, 5)
7. 在Python中,如何構(gòu)建一個模式對象叨叙?
答:在Python的re模塊中锭弊,可以使用compile()方法將正則表達(dá)式編譯生成正則表達(dá)式對象,然后再使用正則表達(dá)式對象提供的方法進(jìn)行字符串處理摔敛,使用編譯后的正則表達(dá)式對象不僅可以提高字符串處理速度廷蓉,還提供了更加強大的字符串處理功能,尤其是對于大文本文件來說,這一步不是強制的桃犬,但推薦這么做刹悴。先來看一下findall的匹配,然后再來看一下“創(chuàng)建”的模式匹配攒暇。
>>> re.findall("[Hh]ello","Hello world, hello Python,!")
['Hello', 'hello']
>>> reg = re.compile("[Hh]ello")
>>> reg.findall("Hello world, hello Python,!")
['Hello', 'hello']
>>>
編譯好的模式可以使用re庫中所有的方法土匀,如下所示:
>>> rgx = re.compile("[Hh]ello")
>>> rgx.search("Hello world, hello Python,!")
<_sre.SRE_Match object; span=(0, 5), match='Hello'>
>>> rgx.match("Hello world, hello Python,!")
<_sre.SRE_Match object; span=(0, 5), match='Hello'>
>>> rgx.findall("Hello world, hello Python, !")
['Hello', 'hello']
Example1:搜索第一個”TAT“重復(fù)序列
import re
seq = "ATATAAGATGCGCGCGCTTATGCGCGCA"
rgx = re.compile("TAT") # 編譯了模式(TAT),編譯好的模式就可以使用re中的方法形用,例如finditer
i = 1
for mo in rgx.finditer(seq): # finditer()方法返回了一個“匹配”類型的對象就轧,就是mo
print('Ocurrence{}:{}'.format(i, mo.group())) # 用group()方法操作了mo對象
print('Position: From {} to {}'.format(mo.start(),mo.end())) # 用span()方法操作了mo對象,
# 這里使用的是mo.start()與mo.end()田度,它們等價于mo.span[0]和mo.span()[1]
# 即價于 print('Position: From {} to {}'.format(mo.span()[0],mo.span()[1]))
i += 1
運行后妒御,結(jié)果如下所示(具體代碼的解釋看注釋):
Ocurrence1:TAT
Position: From 1 to 4
Ocurrence2:TAT
Position: From 18 to 21
8. 如果我要匹配超過一種模式,如何操作镇饺?
答:如果要匹配超過一種模式乎莉,則需要用到組操作(grouping)。用括號()來將標(biāo)一個組奸笤,惋啃。組可以被“捕獲(capturing)或非捕獲(non-capturing),按照這種分類方法监右,組合就有捕獲組和非捕獲組边灭。捕獲組就是把正則表達(dá)式中子表達(dá)式匹配的內(nèi)容,保存到內(nèi)存中以數(shù)字編號或顯式命名的組里健盒,方便檢索绒瘦。groups()
方法可以用于捕獲組,需要注意的是groups()
和group()
是兩種不同的方法扣癣。group()
返回匹配的字符串椭坚,groups()返回的是元組,它們的用法可以用幾個案例來說明搏色,如下所示:
Example2: 常規(guī)匹配
下面的代碼匹配的是“單詞,逗號券册,單詞”這個模式频轿,里面有2個括號,group()默認(rèn)會返回整個匹配結(jié)果烁焙,它等同于group(0)航邢,而group(1)會返回第1個亞組,group(2)會返回第2個亞組骄蝇,關(guān)于亞組的劃分膳殷,如下圖所示:
[圖片上傳失敗...(image-5119-1551584782240)]
import re
m = re.search(r"(\w+)\,(\w+)", "Isaac Newton,physicist")
# 匹配一個“單詞,逗號九火,一個單詞”
m.group()
m.group(0)
print(type(m.group(0)))
# m.group(0)和group()都是返回整個匹配結(jié)果赚窃,就是group(0)的內(nèi)容
# m.group(0)的結(jié)果是一個字符串
m.group(1)
# 返回第1個亞組(就是group(1)的內(nèi)容
m.group(2)
# 返回第2個亞組(就是group(2)的內(nèi)容
m.group(10)
# group一共就0,1,2三個册招,如果是gruop(10)則會出錯
m.group(1,2)
# 輸出多個匹配結(jié)果,m.gorup(1,2)表示輸出
m.groups()
# 返回一個包含所有亞組字符串的元組勒极,從1 到所含的小組號,具體的案例可以往后看
結(jié)果如下所示:
>>> import re
>>> m = re.search(r"(\w+)\,(\w+)", "Isaac Newton,physicist")
>>> # 匹配一個"單詞是掰,逗號,一個單詞"
... m.group()
'Newton,physicist'
>>> m.group(0)
'Newton,physicist'
>>> print(type(m.group(0)))
<class 'str'>
>>> # m.group(0)和group()都是返回整個匹配結(jié)果辱匿,就是group(0)的內(nèi)容
... # m.group(0)的結(jié)果是一個字符串
...
>>> m.group(1)
'Newton'
>>> # 返回第1個亞組(就是group(1)的內(nèi)容
...
>>> m.group(2)
'physicist'
>>> # 返回第2個亞組(就是group(2)的內(nèi)容
>>>
>>> m.groups()
('Newton', 'physicist')
Example 3: gruop(1)的返回值
如果有多個匹配結(jié)果,gruop(1)則返回最后1個匹配結(jié)果,如下所示:
m0 = re.match(r"(..)+", "a1b2c3")
m0.group(0)
m0.group(1)
結(jié)果如下所示:
>>> m0 = re.match(r"(..)+", "a1b2c3")
>>> m0.group(0)
'a1b2c3'
>>> m0.group(1)
'c3'
需要注意的是,m0.group(0)返回的是整個匹配結(jié)果,而group(1)返回的是則是最后1個匹配結(jié)果,因為m0 = re.match(r"(..)+", "a1b2c3")中只有1個括號,它會逐步地進(jìn)行匹配,第1次匹配的是a1,第2次匹配的是b2键痛,此時匹配的結(jié)果是b2,覆蓋掉a1匾七,接著再匹配絮短,是c3,然后c3覆蓋b2昨忆,這是最后的匹配結(jié)果丁频,因此m0.group(1)返回的是就是c3,如果有3個括號扔嵌,就會連續(xù)匹配a1b2c3限府,有3個亞組,即如下代碼:
m01 = re.match(r"(..)(..)(..)+", "a1b2c3")
m01.group()
m01.group(1)
m01.group(2)
m01.group(3)
運行結(jié)果如下所示:
>>> m01 = re.match(r"(..)(..)(..)+", "a1b2c3")
>>> m01.group()
'a1b2c3'
>>> m01.group(1)
'a1'
>>> m01.group(2)
'b2'
>>> m01.group(3)
'c3'
>>>
Example4: group()與groups()返回的數(shù)值類型
group()返回的結(jié)果是一個字符串痢缎,groups()返回的結(jié)果是一個元組胁勺,如下所示:
import re
m = re.search(r"(\w+)\,(\w+)", "Isaac Newton,physicist")
print(type(m.group()))
print(type(m.groups()))
結(jié)果如下所示:
>>> m02.group(2)
'2c'
>>> import re
>>> m = re.search(r"(\w+)\,(\w+)", "Isaac Newton,physicist")
>>> print(type(m.group()))
<class 'str'>
>>> print(type(m.groups()))
<class 'tuple'>
>>>
Example5: group()與groups()的區(qū)別
m2 = re.match(r"(\d)(\d)(\d)(\d)","1234")
m2.group()
m2.group(1)
m2.group(2)
m2.group(3)
m2.group(4)
m2.groups()
結(jié)果如下所示:
>>> m2 = re.match(r"(\d)(\d)(\d)(\d)","1234")
>>> m2.group()
'1234'
>>> m2.group(1)
'1'
>>> m2.group(2)
'2'
>>> m2.group(3)
'3'
>>> m2.group(4)
'4'
>>> m2.groups()
('1', '2', '3', '4')
Example6: group()和groups()的應(yīng)用。
現(xiàn)在一條堿基独旷,它的序列是ATATAAGATGCGCGCGCTTATGCGCGCA署穗,現(xiàn)在找到它的GC序列,代碼如下:
import re
seq = "ATATAAGATGCGCGCGCTTATGCGCGCA"
rgx = re.compile("(GC){3,}")
# (GC){3,}表示至少匹配3次嵌洼,如果有4個連續(xù)的GC也匹配案疲,5個也是如此
result = rgx.search(seq)
result.group()
result.groups()
result.group(0)
result.group(1)
result.group(0,1)
結(jié)果如下所示:
>>> import re
>>> seq = "ATATAAGATGCGCGCGCTTATGCGCGCA"
>>> rgx = re.compile("(GC){3,}")
>>> # (GC){3,}表示至少匹配3次,如果有4個連續(xù)的GC也匹配麻养,5個也是如此
...
>>> result = rgx.search(seq)
>>> result.group()
'GCGCGCGC'
>>> result.groups()
('GC',)
>>> result.group(0)
'GCGCGCGC'
>>> result.group(1)
'GC'
>>> result.group(0,1)
('GCGCGCGC', 'GC')
從結(jié)果中可以看出褐啡,group()如果不填寫參數(shù),或者是填寫了參數(shù)0鳖昌,就會返回完全匹配的子字符串备畦,如果寫了參數(shù)1,會返回第2個匹配結(jié)果许昨,如果填寫了0,1懂盐,則返回所有的匹配結(jié)果。它的原理如下所示:
(GC){3,}
表示表示至少匹配3次糕档,ATATAAGATGCGCGCGCTTATGCGCGCA序列中有GCGCGCGC莉恼,就匹配上了,groups()返回的是一個包含唯一或者全部子組的元組。
捕獲組 | 正則表達(dá)式 | 結(jié)果 |
---|---|---|
group(0) | (GC){3,} | GCGCGCGC |
group(1) | (GC) | GC |
接著再來看一下groups()的使用方法,groups()方法返回的是匹配的所有亞組的結(jié)果俐银,在這種情況下尿背,由于search返回的是一個匹配對象(match object),在模式中有一個組(即GC)悉患,返回的匹配結(jié)果是一個元組(tuple)残家,如下所示:
這種情況,就是常規(guī)的使用方法售躁,跟前面第5個問題中描述的情況一樣坞淮。如果是groups()
方法,它返回的是匹配的所有亞組的結(jié)果陪捷,在這種情況下回窘,由于search返回的是一個匹配對象(match object),在模式中只有一個組(即GC)市袖,返回的匹配結(jié)果是一個元組(tuple)啡直,即("GC",),如果想讓groups返回整個模式苍碟,需要在編譯模式中添加上括號酒觅,像下面這個案例一樣操作:如下所示:
import re
seq = "ATATAAGATGCGCGCGCTTATGCGCGCA"
rgx = re.compile("((GC){3,})")
result = rgx.search(seq)
result.groups()
result.group()
結(jié)果如下所示:
>>> import re
>>> seq = "ATATAAGATGCGCGCGCTTATGCGCGCA"
>>> rgx = re.compile("((GC){3,})")
>>> result = rgx.search(seq)
>>> result.groups()
('GCGCGCGC', 'GC')
在這種模式下,group()與groups()都能被檢索(從左向右)微峰,因為這兩種組都是默認(rèn)能“捕獲”的舷丹。如果不需要內(nèi)部的這個子組(“CG”組),可以將其標(biāo)為非捕獲組(non-capturing)蜓肆,方法就是在組的開始添加上?:
颜凯,如下所示:
import re
seq = "ATATAAGATGCGCGCGCTTATGCGCGCA"
rgx = re.compile("((?:GC){3,})")
result = rgx.search(seq)
result.groups()
result.group()
結(jié)果如下:
>>> import re
>>> seq = "ATATAAGATGCGCGCGCTTATGCGCGCA"
>>> rgx = re.compile("((?:GC){3,})")
>>> result = rgx.search(seq)
>>> result.groups()
('GCGCGCGC',)
>>> result.group()
'GCGCGCGC'
9. re.search()方法匹配的是都是第一個結(jié)果,如何匹配多個結(jié)果仗扬?
答:如果要進(jìn)行所有的匹配症概,需要用到re.findall()方法,它的用法如下:
findall(pattern, string, flags=0)
re.findall()方法能夠以列表的形式返回能匹配的子字符串早芭。如果模式中存在一個組彼城,那么findall也有不同的作用。如果沒有組退个,那么findall返回的是匹配字符串的列表精肃。如果模式中存在組,它會返回含有組的列表帜乞,如果有超過1組,返回一個元組列表筐眷,如下所示:
import re
seq = "ATATAAGATGCGCGCGCTTATGCGCGCA"
rgx = re.compile("TAT")
# 沒有組
rgx.findall(seq)
# 返回匹配的字符串的列表
type(rgx.findall(seq))
rgx = re.compile("(GC){3,}")
# 模式中含有1個組黎烈,返回1個列表
rgx.findall(seq)
# 每個匹配對應(yīng)的組
rgx = re.compile("((GC){3,})")
# 含有2個組,為每個匹配返回一個元組,整體就是一個元組列表
rgx.findall(seq)
rgx = re.compile("((?:GC){3,})")
# 利用非捕獲組得到唯一的匹配
rgx.findall(seq)
結(jié)果如下所示:
>>> import re
>>> seq = "ATATAAGATGCGCGCGCTTATGCGCGCA"
>>> rgx = re.compile("TAT")
>>> # 沒有組照棋,反回字符串列表
... rgx.findall(seq)
['TAT', 'TAT']
>>> # 返回匹配的字符串的列表
... type(rgx.findall(seq))
<class 'list'>
>>> rgx = re.compile("(GC){3,}")
>>> # 模式中含有1個組资溃,返回1個列表
...
>>> rgx.findall(seq)
['GC', 'GC']
>>> # 每個匹配對應(yīng)的組
...
>>> rgx = re.compile("((GC){3,})")
>>> # 含有2個組,為每個匹配返回一個元組烈炭,整體就是一個元組列表
... rgx.findall(seq)
[('GCGCGCGC', 'GC'), ('GCGCGC', 'GC')]
>>> rgx = re.compile("((?:GC){3,})")
>>> # 利用非捕獲組得到唯一的匹配
... rgx.findall(seq)
['GCGCGCGC', 'GCGCGC']
案例第六:尋找多個亞模式(sub-patterns)
不同的組可以用于標(biāo)記溶锭,其格式為?P<組名字>
,如下所示:
import re
rgx = re.compile("(?P<TBX>TATA..).*(?P<CGislands>(?:GC){3,})")
seq = "ATATAAGATGCGCGCGCTTATGCGCGCA"
result = rgx.search(seq)
print(result.group('CGislands'))
print(result.group('TBX'))
結(jié)果如下所示:
C:\Users\20161111>python t.py
GCGCGC
TATAAG
Example7:用戶支持的模式匹配行
這行代碼主要是為了統(tǒng)計某個單詞在文本文件中有多少個符隙,代碼如下:
import re, sys
myregex = re.compile(sys.argv[2])
counter = 0
fh = open(sys.argv[1])
for line in fh:
if myregex.search(line):
counter += 1
fh.closer()
print(counter)
代碼解釋如下:
第一趴捅,第2行代碼:關(guān)于sys.argv[2]的用法,舉1個小例子霹疫,在C盤的C:\Users\20161111
目錄下建立一個.py
腳本拱绑,命名為test.py
,輸入下面的代碼:
import sys
a = sys.argv[0]
print(a)
保存丽蝎,快捷鍵Win+R
猎拨,打開cmd,輸入python test.py
屠阻,結(jié)果如下所示:
C:\Users\20161111>python test.py
test.py
由此可見红省,sys.argv[0]表示的就是test.py
這個文件本身,現(xiàn)在將tetst.py
代碼中的sys.argv[0]更改為sys.argv[1]
,再次運行国觉,輸入python test.py what
吧恃,如下所示:
C:\Users\20161111>python test.py what
what
運行的結(jié)果變成了what,再次修改蛉加,將sys.argv[1]改為sys.argv[2:]蚜枢,運行,輸入python test.py test0 what1 how3 apple4
针饥,如下所示:
C:\Users\20161111>python test.py test0 what1 how3 apple4
['what1', 'how3', 'apple4']
C:\Users\20161111>
得到的結(jié)果是:'what1', 'how3', 'apple4'厂抽。再倒回去想一下,sys.argv[0]表示的是test.py本身丁眼,sys.argv[1]表示的是輸入的第1個參數(shù)筷凤,sys.argv[2:]表示的是第2個參數(shù)往后,這與切片的表示形式是一樣的苞七。
結(jié)論就是藐守,sys.argv[ ]其實就是一個列表,里邊的項為用戶輸入的參數(shù)蹂风,關(guān)鍵就是要明白這參數(shù)是從程序外部輸入的卢厂,而非代碼本身的什么地方,要想看到它的效果就應(yīng)該將程序保存了惠啄,從外部來運行程序并給出參數(shù)(參考資料:Python中 sys.argv[]的用法簡明解釋)慎恒。
第二任内,第4行代碼,fh = open(sys.argv[1])表示的就是打開某個文件融柬。
第三死嗦,現(xiàn)在運行一下這個腳本,將腳本保存到C盤的根目錄下粒氧,命名為count_line.py
越除,同時在同一個目錄新建一個文本文件,輸入以下文字:
line1
line2
line3
line4
將文件命名為line_test.txt
外盯,打開cmd摘盆,輸入命令python count_line.py count_test,line
,一共是2個參數(shù)(前面的python不算)门怪,參數(shù)1是腳本名稱骡澈,即count_line.py,參數(shù)2是文本文件掷空,即count_test肋殴,參數(shù)3是要統(tǒng)計的文字,即line坦弟,運行結(jié)果如下所示:
C:\Users\20161111>python count_line.py line_test.txt line
4
可以發(fā)現(xiàn)护锤,這個文本文件中有4個line這個單詞。但是這個腳本有個缺陷酿傍,就是烙懦,如果一行中有兩個line這個單詞,它還是會統(tǒng)計為1個赤炒,如下所示氯析,將文本文件更改為這樣的:
line1
line2
line3
line4 line5
繼續(xù)運行上述腳本,結(jié)果如下所示:
C:\Users\20161111>python count_line.py line_test.txt line
4
因此莺褒,需要對腳本進(jìn)行更改掩缓,更改后的版本如下所示:
import re, sys
myregex = re.compile(sys.argv[2])
counter = 0
fh = open(sys.argv[1])
for line in fh:
counter += len(myregex.findall(line))
fh.close()
print(counter)
運行結(jié)果如下所示:
C:\Users\20161111>python count_line.py line_test.txt line
5
10. 在Python中,正則表達(dá)式的規(guī)則非常難記遵岩,有沒有工具可以用來檢測正則表達(dá)式的正確與否你辣?
答:有個工具是Kodos,這個工具是用Python寫成的尘执,輸入正則表達(dá)式舍哄,它能夠在相應(yīng)的輸出框顯示出正則表達(dá)式的結(jié)查,官網(wǎng)是:http://kodos.sourceforge.net/誊锭,軟件是在WIndows下運行的表悬,打開后界面如下所示:
[圖片上傳失敗...(image-2b5ea4-1551584782240)]
11. 如何通過正則表達(dá)式替換一些字符串?
答:如果要實現(xiàn)這個目的丧靡,需要用到re.sub()方法蟆沫,sub就是substitution的簡寫叉讥,它的用法是sub(rpl,str[,count=0])
具體參數(shù)的含義如下所示:
- rpl:原始的字符串;
- str饥追,需要替換原始字符串的字符串。
- [,count=0]罐盔,可選參數(shù)但绕,表示替換的最大次數(shù),默認(rèn)是0惶看,表示替換所有匹配捏顺。
re.sub的使用非常類似于replace方法,參見下面的案例纬黎,代碼如下所示:
這個案例展示的是:刪除GC重復(fù)(該行有超過3個GC)幅骄,代碼解釋參見注釋
import re
regex = re.compile("(?:GC){3,}") # 匹配至少3個GC結(jié)邊的字符串
seq = "ATGATCGTACTGCGCGCTTCATGTGATGCGCGCGCGCAGACTATAAG"
print("Before:", seq)
print("After:", regex.sub("",seq))
結(jié)果如下所示:
C:\Users\20161111>python test.py
Before: ATGATCGTACTGCGCGCTTCATGTGATGCGCGCGCGCAGACTATAAG
After: ATGATCGTACTTTCATGTGATAGACTATAAG
第二個方法:subn(rpl,str[,count=0])
也能實現(xiàn)re.sub
的功能。
不同之處在于本今,subn會返回替換后的字符串和替換的次數(shù)拆座,將上述代碼用subn演示,就如下所示:
import re
regex = re.compile("(?:GC){3,}") # 匹配至少3個GC結(jié)邊的字符串
seq = "ATGATCGTACTGCGCGCTTCATGTGATGCGCGCGCGCAGACTATAAG"
print("Before:", seq)
print("After:", regex.subn("",seq))
結(jié)果如下所示:
C:\Users\20161111>python test.py
Before: ATGATCGTACTGCGCGCTTCATGTGATGCGCGCGCGCAGACTATAAG
After: ('ATGATCGTACTTTCATGTGATAGACTATAAG', 2)
12. 正則表達(dá)式在生物信息學(xué)方面有什么用處冠息?
答:正則表達(dá)式可以用于搜索PROSITE(這是一個蛋白質(zhì)拉點和序列模式數(shù)據(jù)庫)挪凑,這個數(shù)據(jù)庫的信息模式就是序列與描述序列的字符串。例如下面的這段字符串:
K-[KR]-C-G-H-[LMQR]
逛艰,這段字符串表示的是異檸檬酸酶的活性位點躏碳。具體的每個字母含義如下:
位于第1個位置的是K,位于第2個位置提是K或R散怖,隨后是CGH菇绵,最后是一段氨基酸序列,即L镇眷,M咬最,Q或R。如果要在這個序列中搜索偏灿,必須要把PROSITE的格式轉(zhuǎn)化為符合Python正則表達(dá)式的表示方式丹诀,就像這樣K[KR]CGH[LMQR]
。
為了將PROSITE轉(zhuǎn)化為REGEX的基本格式翁垂,這個過程中包括移除連接符(“-”)铆遭,將括號之間的數(shù)字替換為大括號之間的數(shù)字,并將“x”替換為點號沿猜,接著看一個腺苷酸環(huán)化酶相關(guān)蛋白2( adenylyl cyclase associated protein 2)的例子枚荣。
此蛋白在PROSITE中的版本如下:
[LIVM](2)-x-R-L-[DE]-x(4)-R-L-E
,這種序列是一致性模式(Consensus pattern)啼肩。
其中橄妆,L是亮氨酸衙伶,I是異亮氨酸,V是纈氨酸害碾,M是甲硫氨酸矢劲,x代表任意氨基酸,R是精氨酸慌随,D是天冬氨酸芬沉,E是谷氨酸。
REGEX(正則表達(dá)式)版本如下:
[LIVM]{2}.RL[DE].{4}RLE
Example8:在FASTA格式中搜索蛋白質(zhì)的模式
現(xiàn)在假設(shè)我們要在一個FASTA格式的文件中尋找這個模式阁猜。除了要找到這個模式外丸逸,我們有可能還需要在上下文中檢索它的位置,即位于在這個模式之前與之后的10個氨基酸序列(代碼中用小寫字母表示)剃袍,下面是一個Fasta格式的文件:
>Q5R5X8|CAP2_PONPY CAP 2 - Pongo pygmaeus (Orangutan).
MANMQGLVERLERAVSRLESLSAESHRPPGNCGEVNGVIGGVAPSVEAFDKLMDSMVAEFLKNSRILAGDVETHAEMVHSAFQAQRAFLLMASQYQQPHENDVAALLKPISEKIQEIQTFRERNRGSNMFNHLSAVSESIPALGWIAVSPKPGPYVKEMNDAATFYTNRVLKDYKHSDLRHVDWVKSYLNIWSELQAYIKEHHTTGLTWSKTGPVASTVSAFSVLSSGPGLPPPPPPPPPPGPPPLLENEGKKEESSPSRSALFAQLNQGEAITKGLRHVTDDQKTYKNPSLRAQGGQTRSPTKSHTPSPTSPKSYPSQKHAPVLELEGKKWRVEYQEDRNDLVISETELKQVAYIFKCEKSTLQIKGKVNSIIIDNCKKLGLVFDNVVGIVEVINSQDIQIQVMGRVPTISINKTEGCHIYLSEDALDCEIVSAKSSEMNILIPQDGDYREFPIPEQFKTAWDGSKLITEPAEIMA
下面的代碼實現(xiàn)的就是這個功能黄刚,即在1個FASTA文件中尋找這個模式,代碼如下:
import re
pattern = "[LIVM]{2}.RL[DE].{4}RLE"
fh = open('D:/prot.fas')
fh.readline()
seq = ""
for line in fh:
seq += line.strip()
rgx = re.compile(pattern)
result = rgx.search(seq)
patternfound = result.group()
span = result.span()
leftpos = span[0]-10
if leftpos < 0:
leftpos = 0
print(seq[leftpos:span[0]].lower() + patternfound + seq[span[1]:span[1]+10].lower())
fh.close()
運行代碼如下所示:
C:\Users\20161111>python test.py
manmqgLVERLERAVSRLEslsaeshrpp
Example9: 清洗序列
正則表達(dá)式在清除序列方面更加常用民效,需要清理的序列通常是一些非標(biāo)準(zhǔn)的序列憔维,就像下面的這樣:
1 ATGACCATGA TTACGCCAAG CTCTAATACG ACTCACTATA GGGAAAGCTT GCATGCCTGC
61 AGGTCGACTC TAGAGGATCT ACTAGTCATA TGGATATCGG ATCCCCGGGT ACCGAGCTCG
121 AATTCACTGG CCGTCGTTTT
這個序列里面有空格,有數(shù)字研铆,這些都不是我們所需要的埋同,需要把它們的清除掉,清除序列的代碼如下所示:
import re
regex = re.compile(' |\d|\n|\t') # 有一個空格
seq = ''
for line in open('D:/pMOSBlue.txt'):
seq += regex.sub('',line)
print(seq)
結(jié)果如下所示:
C:\Users\20161111>python test.py
ATGACCATGATTACGCCAAGCTCTAATACGACTCACTATAGGGAAAGCTTGCATGCCTGCAGGTCGACTCTAGAGGATCTACTAGTCATATGGATATCGGATCCCCGGGTACCGAGCTCGAATTCACTGGCCGTCGTTTT
代碼解釋:最重要的就是這個模式:regex = re.compile(' |\d|\n|\t')
棵红,其中' |\d|\n|\t'表示的是凶赁,數(shù)字或換行,或空格逆甜。