Python正則表達(dá)式

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"伙窃,還有一些特殊的字符用于特殊的匹配,以. ^ $ * + ? { [ ] \ | ( )為例說明一下样漆,如下表所示:

  1. .號:匹配除除換行符 \n 之外的任何字符为障,例如“ATT.T”會匹配“ATTCT”,"ATTFT"放祟,但不會匹配“ATTTCT”鳍怨。

  2. ^(克拉符號):匹配輸入字符串的開始位置,例如“AUG”會匹配“AUGAGC”跪妥,但不匹配“AAUGC”鞋喇。如果是在方括號里使用,例如[^AUG]表示相反的意思眉撵,即不匹配以AUG開頭的字符串侦香。

  3. $(美元符號):在一行字符串中落塑,匹配輸入字符串的結(jié)尾位置谱醇,例如“UAA$”匹配“AGCUAA”资盅,但不匹配“ACUAAG”颜曾。

  4. *(星號):匹配前面的子表達(dá)式零次或多次重復(fù)岭粤。例如“AT*”會匹配“AAT”,“A”十籍,但不匹配“TT”箱硕。

  5. +(加號):匹配前面的子表達(dá)式一次或多次重復(fù)期揪》溃“AT+”會匹配“ATT”晦款,但不匹配“A”。

  6. ?匹配前面的子表達(dá)式零次或一次重復(fù)顷锰,“AT?”會匹配“A”或“AT”柬赐。

  7. (...)(括號):匹配圓括號中的表達(dá)式,用于表明匹配的開始與結(jié)構(gòu)官紫,如果只匹配括號,例如匹配“(”或“)”時州藕,可以使用(或)束世,或者是將它們放到中括號里[(][)]。

  8. (?:...):匹配但不捕獲該匹配的子表達(dá)式床玻。

  9. {n}:n是一個非負(fù)整數(shù)毁涉,匹配重復(fù)的某字符串的n次。例如锈死,“(ATTG){3}”匹配ATTGATTGATTG贫堰,但是不匹配“ATTGATTG”。(第1個是重復(fù)了3次待牵,第2個是重復(fù)了2次)其屏。

  10. {m,n}:m和n均為非負(fù)整數(shù),其中m<=n缨该,它表示最少匹配n次且最多匹配m次偎行。例如“(AT){3,5}”會匹配“ATATTATATAT”,但是不匹配“ATATTATAT”贰拿,如果不加m蛤袒,則是從匹配0次的開始,如果沒有n膨更,則匹配任意重復(fù)的某字符串妙真。

  11. []:表示一組字符串〖允兀“[A-Z]”會匹配任何大寫的字母珍德,而“[a-z0-9]”則會匹配任何小寫的字母以及數(shù)字练般。“[AT]”匹配“A”菱阵,“T”踢俄,或“(星號)”。在中括號里晴及,^表示相反的含義都办,例如“[^R]”會匹配任何除了“R”之外的字母。

  12. \:將下一個字符標(biāo)記為或特殊字符虑稼、或原義字符琳钉、或向后引用、或八進(jìn)制轉(zhuǎn)義符蛛倦。例如歌懒, 'n' 匹配字符 'n'。'\n' 匹配換行符溯壶。序列 '\' 匹配 ""及皂,而 '(' 則匹配 "("。

  13. |:表達(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ù)的含義如下所示:

  1. rpl:原始的字符串;
  2. str饥追,需要替換原始字符串的字符串。
  3. [,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ù)字或換行,或空格逆甜。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末虱肄,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子交煞,更是在濱河造成了極大的恐慌咏窿,老刑警劉巖,帶你破解...
    沈念sama閱讀 218,682評論 6 507
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件素征,死亡現(xiàn)場離奇詭異集嵌,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)御毅,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,277評論 3 395
  • 文/潘曉璐 我一進(jìn)店門根欧,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人端蛆,你說我怎么就攤上這事凤粗。” “怎么了今豆?”我有些...
    開封第一講書人閱讀 165,083評論 0 355
  • 文/不壞的土叔 我叫張陵嫌拣,是天一觀的道長柔袁。 經(jīng)常有香客問我,道長异逐,這世上最難降的妖魔是什么捶索? 我笑而不...
    開封第一講書人閱讀 58,763評論 1 295
  • 正文 為了忘掉前任,我火速辦了婚禮灰瞻,結(jié)果婚禮上情组,老公的妹妹穿的比我還像新娘。我一直安慰自己箩祥,他們只是感情好,可當(dāng)我...
    茶點故事閱讀 67,785評論 6 392
  • 文/花漫 我一把揭開白布肆氓。 她就那樣靜靜地躺著袍祖,像睡著了一般。 火紅的嫁衣襯著肌膚如雪谢揪。 梳的紋絲不亂的頭發(fā)上蕉陋,一...
    開封第一講書人閱讀 51,624評論 1 305
  • 那天,我揣著相機(jī)與錄音拨扶,去河邊找鬼凳鬓。 笑死,一個胖子當(dāng)著我的面吹牛患民,可吹牛的內(nèi)容都是我干的缩举。 我是一名探鬼主播,決...
    沈念sama閱讀 40,358評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼匹颤,長吁一口氣:“原來是場噩夢啊……” “哼仅孩!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起印蓖,我...
    開封第一講書人閱讀 39,261評論 0 276
  • 序言:老撾萬榮一對情侶失蹤辽慕,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后赦肃,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體溅蛉,經(jīng)...
    沈念sama閱讀 45,722評論 1 315
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,900評論 3 336
  • 正文 我和宋清朗相戀三年他宛,在試婚紗的時候發(fā)現(xiàn)自己被綠了船侧。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 40,030評論 1 350
  • 序言:一個原本活蹦亂跳的男人離奇死亡堕汞,死狀恐怖勺爱,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情讯检,我是刑警寧澤琐鲁,帶...
    沈念sama閱讀 35,737評論 5 346
  • 正文 年R本政府宣布卫旱,位于F島的核電站,受9級特大地震影響围段,放射性物質(zhì)發(fā)生泄漏顾翼。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 41,360評論 3 330
  • 文/蒙蒙 一奈泪、第九天 我趴在偏房一處隱蔽的房頂上張望适贸。 院中可真熱鬧,春花似錦涝桅、人聲如沸拜姿。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,941評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽蕊肥。三九已至,卻和暖如春蛤肌,著一層夾襖步出監(jiān)牢的瞬間壁却,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,057評論 1 270
  • 我被黑心中介騙來泰國打工裸准, 沒想到剛下飛機(jī)就差點兒被人妖公主榨干…… 1. 我叫王不留展东,地道東北人。 一個月前我還...
    沈念sama閱讀 48,237評論 3 371
  • 正文 我出身青樓炒俱,卻偏偏與公主長得像盐肃,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子权悟,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 44,976評論 2 355

推薦閱讀更多精彩內(nèi)容

  • re模塊手冊 本模塊提供了和Perl里的正則表達(dá)式類似的功能恼蓬,不關(guān)是正則表達(dá)式本身還是被搜索的字符串,都可以...
    喜歡吃栗子閱讀 4,010評論 0 13
  • 搞懂Python 正則表達(dá)式用法 Python 正則表達(dá)式 正則表達(dá)式是一個特殊的字符序列僵芹,它能幫助你方便的檢查一...
    廈熱閱讀 1,583評論 0 2
  • #首先馏段,python中的正則表達(dá)式大致分為以下幾部分: 元字符 模式 函數(shù) re 內(nèi)置對象用法 分組用法 環(huán)視用法...
    mapuboy閱讀 1,610評論 0 51
  • 一谐宙、正則表達(dá)式正則表達(dá)式(regular expression)是由一些特定字符以及組合所組成的字符串表達(dá)式皂股,用來...
    IIronMan閱讀 1,885評論 0 24
  • 如果相愛浪漫途戒, 錯過也是美的留言。 眼眸里寫滿癡情件豌, 相知溫暖疮方。 命運多般不得不已, 淹沒了世俗虛妄茧彤。 靈魂里映照...
    心羽自心閱讀 164評論 0 1