re模塊和字符串處理python
對於簡單的匹配,一般有str.find(),str.endswith(), str.startswith()正則表達式
>>>text = 'abcd'
>>> text.startswith('a')
True
>>> text.startswith('b')
False
>>> text.endswith('d')
True
>>> text.find('c')
2
>>> text[2]
'c'
對於比較複雜的匹配就須要用到正則表達式和re模塊了緩存
>>> text1 = '4/24/2019'
>>> text2 = '2019.4.24'
>>> import re
>>> re.match(r'\d+/\d+/\d+', text1)
<re.Match object; span=(0, 9), match='4/24/2019'> #匹配成功
>>> re.match(r'\d+/\d+/\d+', text2) #匹配失敗,沒有返回Mathch對象
#若是想用同一個模式匹配多個字符串,那麼把模式字符串預編譯爲模式對象
>>> c = re.compile(r'\d+/\d+/\d+')
>>> c
re.compile('\\d+/\\d+/\\d+')
>>> c.match(text1) #用編譯好的模式匹配字符串
<re.Match object; span=(0, 9), match='4/24/2019'>
#match老是從字符串開始處匹配,想查找字符串與模式匹配的全部位置用findall
>>> text = 'Today is 11/27/2012. PyCon starts 3/13/2013.'
>>> c.findall(text) #若是用match就會匹配失敗,由於它老是從開始第一個字母對比匹配
['11/27/2012', '3/13/2013']
在定義正則式的時候,一般會用括號去捕獲分組函數
>>> c = re.compile(r'(\d+)/(\d+)/(\d+)')
>>> m = c.match('4/24/2019')
>>> m.group() #等於group(0)
'4/24/2019'
>>> m.group(0) #捕獲所有分組
'4/24/2019'
>>> m.group(1) #捕獲第一個分組
'4'
>>> m.groups() #捕獲全部分組,返回一個元組
('4', '24', '2019')
>>> text = 'Today is 11/27/2012. PyCon starts 3/13/2013.'
>>> f = c.findall(text) #返回一個全部位置匹配成功的列表
>>> f
[('11', '27', '2012'), ('3', '13', '2013')]
>>> for month, day, year in c.findall(text):
print('{}-{}-{}'.format(year, month, day))
2012-11-27
2013-3-13
#finditer()返回一個可迭代對象,每一個元素都爲一個Match對象
>>> c.finditer(text)
<callable_iterator object at 0x0000018954FDE6A0>
>>> for i in c.finditer(text):
... print(i)
<re.Match object; span=(9, 19), match='11/27/2012'>
<re.Match object; span=(34, 43), match='3/13/2013'>
>>> for i in c.finditer(text):
print(i.group(3))
2012
2013
>>> for i in c.finditer(text):
print(i.groups())
('11', '27', '2012')
('3', '13', '2013')
match()方法僅會匹配字符串開始處,能匹配到就返回匹配到的部分,若是想以正則表達式精確匹配整個字符串那麼就要在正則表達式結尾加 $。性能
>>> c
re.compile('(\\d+)/(\\d+)/(\\d+)')
>>> m = c.match('11/27/2012abcdef') #此時把開頭匹配到的返回了
>>> m
<re.Match object; span=(0, 10), match='11/27/2012'>
>>> m.group(0)
'11/27/2012'
>>> c = re.compile(r'(\d+)/(\d+)/(\d+)$') #以 $ 結尾時只有匹配整個字符串纔會匹配成功
>>> m = c.match('11/27/2012abcdef')
>>> m #沒有值
可是須要注意的是,若是你打算作大量的匹配和搜索操做的話,最好先編譯正則表
達式,而後再重複使用它。模塊級別的函數會將最近編譯過的模式緩存起來,所以並
不會消耗太多的性能,可是若是使用預編譯模式的話,你將會減小查找和一些額外的
處理損耗**ui
對於簡單的字符串替換,通常用replace()便可this
>>> t = 'yes, no'
>>> t.replace('yes', 'no')
'no, no'
對於複雜的模式。就須要用到re模塊的sub()函數spa
>>> text = 'Today is 11/27/2012. PyCon starts 3/13/2013.'
>>> re.sub(r'(\d+)/(\d+)/(\d+)', r'\3-\1\2-', text)
'Today is 2012-1127-. PyCon starts 2013-313-.'
#sub()函數第一個參數是匹配模式,第二個參數是替換模式反斜槓加數字表示匹配捕獲的組號
#若是你打算用相同的模式作屢次替換考慮先編譯它來提高性能好比:
>>> import re
>>> datepat = re.compile(r'(\d+)/(\d+)/(\d+)')
>>> datepat.sub(r'\3-\1-\2', text)
'Today is 2012-11-27. PyCon starts 2013-3-13.'
以忽略大小寫的方式搜索與替換文本字符串code
#爲了在文本操做時忽略大小寫,你須要在使用 re 模塊的時候給這些操做提供re.IGNORECASE 標誌參數。好比:
>>> text = 'UPPER PYTHON, lower python, Mixed Python'
>>> re.findall('python', text, flags=re.IGNORECASE)
['PYTHON', 'python', 'Python']
>>> re.sub('python', 'snake', text, flags=re.IGNORECASE)
'UPPER snake, lower snake, Mixed snake'
非貪婪匹配orm
#這個問題通常出如今須要匹配一對分隔符之間的文本的時候 (好比引號包含的字符串)。
>>> c = re.compile(r'\"(.*)\"')
>>> c
re.compile('\\"(.*)\\"')
>>> text1 = 'Computer says "no."'
>>> c.findall(text1)
['no.'] #正確匹配
>>> text2 = 'Computer says "no." Phone says "yes."'
>>> c.findall(text2)
['no." Phone says "yes.'] #!這時應該匹配['no', 'yes']
#在這個例子中,模式 r'\"(.*)\"' 的意圖是匹配被雙引號包含的文本。可是在正則表達式中 * 操做符是貪婪的,所以匹配操做會查找最長的可能匹配。因而在第二個例子中搜索 text2 的時候返回結果並非咱們想要的。
#爲了修正這個問題,能夠在模式中的 * 操做符後面加上? 修飾符
>>> c = re.compile(r'\"(.*?)\"')
>>> c.findall(text2)
['no.', 'yes.'] #這樣就會使匹配變成非貪婪的
多行匹配換行符
# (.)不能匹配換行符
>>> comment = re.compile(r'/\*(.*?)\*/') #/\*, /是轉義字符,匹配\*
>>> text1 = '/* this is a comment */'
>>> text2 = '''/* this is a
... multiline comment */
... '''
>>>
>>> comment.findall(text1)
[' this is a comment ']
>>> comment.findall(text2) #(.)匹配除了換行的任意字符。若是指定了標籤 DOTALL ,它將匹配包括換行符的任意字符。此時字符串中間有換行符,匹配失敗
[]
#re.compile() 函數接受一個標誌參數叫 re.DOTALL ,在這裏很是有用。它可讓正則表達式中的點 (.) 匹配包括換行符在內的任意字符。好比:
>>> comment = re.compile(r'/\*(.*?)\*/', re.DOTALL)
>>> comment.findall(text2)
[' this is a\n multiline comment ']
字符串對齊:format函數
#順便寫下來format吧。。
>>> format(text, '>20')
' Hello World'
>>> format(text, '<20')
'Hello World '
>>> format(text, '^20')
' Hello World '
>>>
#若是你想指定一個非空格的填充字符,將它寫到對齊字符的前面便可
>>> format(text, '=>20s')
'=========Hello World'
>>> format(text, '*^20s')
'****Hello World*****'
#當格式化多個值的時候,這些格式代碼也能夠被用在 format() 方法中
>>> '{:>10s} {:>10s}'.format('Hello', 'World')
' Hello World'
#format() 函數的一個好處是它不只適用於字符串。它能夠用來格式化任何值,使得它很是的通用
>>> x = 1.2345
>>> format(x, '>10')
' 1.2345'
>>> format(x, '^10.2f')
' 1.23 '
當你想要拼接列表中的字符串和數字時,最有效的方法是生成器
>>> data = ['ACME', 50, 91.1]
>>> ','.join(str(d) for d in data)
'ACME,50,91.1
你想建立一個內嵌變量的字符串,變量被它的值所表示的字符串替換掉
#通常狀況下能夠用format來實現
>>> s = '{name} has {n} messages.'
>>> s.format(name='Guido', n=37)
'Guido has 37 messages.'
#若是要被替換的變量能在變量域中找到,那麼你能夠結合使用 format map()和 vars()
>>> name = 'yang'
>>> n = 21
>>> s.format_map(vars())
'yang has 21 messages.'
- .
(點) 在默認模式,匹配除了換行的任意字符。若是指定了標籤 DOTALL ,它將匹配包括換行符的任意字符。
- ^
(插入符號) 匹配字符串的開頭, 而且在 MULTILINE 模式也匹配換行後的首個符號。
- $
匹配字符串尾或者換行符的前一個字符,在 MULTILINE 模式匹配換行符的前一個字符。 foo 匹配 'foo' 和 'foobar' , 但正則 foo$ 只匹配 'foo'。更有趣的是, 在 'foo1\nfoo2\n' 搜索 foo.$ ,一般匹配 'foo2' ,但在 MULTILINE 模式 ,能夠匹配到 'foo1' ;在 'foon' 搜索 $ 會找到兩個空串:一個在換行前,一個在字符串最後。
- *
對它前面的正則式匹配0到任意次重複, 儘可能多的匹配字符串。 ab* 會匹配 'a', 'ab', 或者 'a'後面跟隨任意個
'b'。
- +
對它前面的正則式匹配1到任意次重複。 ab+ 會匹配 'a' 後面跟隨1個以上到任意個 'b',它不會匹配 'a'。
- ?
對它前面的正則式匹配0到1次重複。 ab? 會匹配 'a' 或者 'ab'。
- *?, +?, ??
'', '+',和 '?' 修飾符都是 貪婪的;它們在字符串進行儘量多的匹配。有時候並不須要這種行爲。若是正則式 <.> 但願找到 ' b <c>',它將會匹配整個字符串,而不只是 ''。在修飾符以後添加 ? 將使樣式以 非貪婪方式或者 :dfn:最小 方式進行匹配; 儘可能 少 的字符將會被匹配。 使用正則式 <.*?> 將會僅僅匹配 ''。
- "{m}"
對其以前的正則式指定匹配 m 個重複;少於 m 的話就會致使匹配失敗。好比, a{6} 將匹配6個 'a' , 可是不能是5個。
- "{m, n}"
對正則式進行 m 到 n 次匹配,在 m 和 n 之間取儘可能多。 好比,a{3,5} 將匹配 3 到 5個 'a'。忽略 m 意爲指定下界爲0,忽略 n 指定上界爲無限次。 好比 a{4,}b 將匹配 'aaaab' 或者1000個 'a' 尾隨一個 'b',但不能匹配 'aaab'。逗號不能省略,不然沒法辨別修飾符應該忽略哪一個邊界。
- {m,n}?
前一個修飾符的非貪婪模式,只匹配儘可能少的字符次數。好比,對於 'aaaaaa', a{3,5} 匹配 5個 'a' ,而 a{3,5}? 只匹配3個 'a'。
- \
轉義特殊字符(容許你匹配 '*', '?', 或者此類其餘),或者表示一個特殊序列;特殊序列以後進行討論。 若是你沒有使用原始字符串( r'raw' )來表達樣式,要牢記Python也使用反斜槓做爲轉義序列;若是轉義序列不被Python的分析器識別,反斜槓和字符才能出如今字符串中。若是Python能夠識別這個序列,那麼反斜槓就應該重複兩次。這將致使理解障礙,因此高度推薦,就算是最簡單的表達式,也要使用原始字符串。
- []
用於表示一個字符集合。在一個集合中: 字符能夠單獨列出,好比 [amk] 匹配 'a', 'm', 或者 'k'。 能夠表示字符範圍,經過用 '-' 將兩個字符連起來。好比 [a-z] 將匹配任何小寫ASCII字符, 0-5 將匹配從 00 到 59 的兩位數字, [0-9A-Fa-f] 將匹配任何十六進制數位。 若是 - 進行了轉義 (好比 [a-z])或者它的位置在首位或者末尾(如 [-a] 或 [a-]),它就只表示普通字符 '-'。 特殊字符在集合中,失去它的特殊含義。好比 [(+)] 只會匹配這幾個文法字符 '(', '+', '', or ')'。 字符類如 w 或者 S (以下定義) 在集合內能夠接受,它們能夠匹配的字符由 ASCII 或者 LOCALE 模式決定。 不在集合範圍內的字符能夠經過 取反 來進行匹配。若是集合首字符是 '^' ,全部 不 在集合內的字符將會被匹配,好比 將匹配全部字符,除了 '5', 將匹配全部字符,除了 '^'. ^ 若是不在集合首位,就沒有特殊含義。 在集合內要匹配一個字符 ']',有兩種方法,要麼就在它以前加上反斜槓,要麼就把它放到集合首位。好比, [()[]{}] 和 []()[{}] 均可以匹配括號。 Unicode Technical Standard #18 裏的嵌套集合和集合操做支持可能在將來添加。這將會改變語法,因此爲了幫助這個改變,一個 FutureWarning 將會在有多義的狀況裏被 raise,包含如下幾種狀況,集合由 '[' 開始,或者包含下列字符序列 '--', '&&', '~~', 和 '||'。爲了不警告,須要將它們用反斜槓轉義。 在 3.7 版更改: 若是一個字符串構建的語義在將來會改變的話,一個 FutureWarning 會 raise 。
- |
A|B, A 和 B 能夠是任意正則表達式,建立一個正則表達式,匹配 A 或者 B. 任意個正則表達式能夠用 '|' 鏈接。它也能夠在組合(見下列)內使用。掃描目標字符串時, '|' 分隔開的正則樣式從左到右進行匹配。當一個樣式徹底匹配時,這個分支就被接受。意思就是,一旦 A 匹配成功, B 就再也不進行匹配,即使它能產生一個更好的匹配。或者說,'|' 操做符毫不貪婪。 若是要匹配 '|' 字符,使用 |, 或者把它包含在字符集裏,好比 [|].
- (...)
(組合),匹配括號內的任意正則表達式,並標識出組合的開始和結尾。匹配完成後,組合的內容能夠被獲取,並能夠在以後用 number 轉義序列進行再次匹配,以後進行詳細說明。要匹配字符 '(' 或者 ')', 用 ( 或 ), 或者把它們包含在字符集合裏: [(], [)].
- (?…)
這是個擴展標記法 (一個 '?' 跟隨 '(' 並沒有含義)。 '?' 後面的第一個字符決定了這個構建採用什麼樣的語法。這種擴展一般並不建立新的組合; (?P<name>...) 是惟一的例外。 如下是目前支持的擴展。
- (?aiLmsux)
( 'a', 'i', 'L', 'm', 's', 'u', 'x' 中的一個或多個) 這個組合匹配一個空字符串;這些字符對正則表達式設置如下標記 re.A (只匹配ASCII字符), re.I (忽略大小寫), re.L (語言依賴), re.M (多行模式), re.S (點dot匹配所有字符), re.U (Unicode匹配), and re.X (冗長模式)。 (這些標記在 模塊內容 中描述) 若是你想將這些標記包含在正則表達式中,這個方法就頗有用,免去了在 re.compile() 中傳遞 flag 參數。標記應該在表達式字符串首位表示。
- (?:…)
正則括號的非捕獲版本。 匹配在括號內的任何正則表達式,但該分組所匹配的子字符串 不能 在執行匹配後被獲取或是以後在模式中被引用。
- (?aiLmsux-imsx:…)
('a', 'i', 'L', 'm', 's', 'u', 'x' 中的0或者多個, 以後可選跟隨 '-' 在後面跟隨 'i' , 'm' , 's' , 'x' 中的一到多個 .) 這些字符爲表達式的其中一部分 設置 或者 去除 相應標記 re.A (只匹配ASCII), re.I (忽略大小寫), re.L (語言依賴), re.M (多行), re.S (點匹配全部字符), re.U (Unicode匹配), and re.X (冗長模式)。(標記描述在 模塊內容 .) 'a', 'L' and 'u' 做爲內聯標記是相互排斥的, 因此它們不能結合在一塊兒,或者跟隨 '-' 。 當他們中的某個出如今內聯組中,它就覆蓋了括號組內的匹配模式。在Unicode樣式中, (?a:...) 切換爲 只匹配ASCII, (?u:...) 切換爲Unicode匹配 (默認). 在byte樣式中 (?L:...) 切換爲語言依賴模式, (?a:...) 切換爲 只匹配ASCII (默認)。這種方式只覆蓋組合內匹配,括號外的匹配模式不受影響。 3.6 新版功能. 在 3.7 版更改: 符號 'a', 'L' 和 'u' 一樣能夠用在一個組合內。
- (?P<name>…)
(命名組合)相似正則組合,可是匹配到的子串組在外部是經過定義的 name 來獲取的。組合名必須是有效的Python標識符,而且每一個組合名只能用一個正則表達式定義,只能定義一次。一個符號組合一樣是一個數字組合,就像這個組合沒有被命名同樣。 命名組合能夠在三種上下文中引用。若是樣式是 (?P<quote>['"]).*?(?P=quote) (也就是說,匹配單引號或者雙引號括起來的字符串): 引用組合 "quote" 的上下文 引用方法 在正則式自身內 (?P=quote) (如示) 1 處理匹配對象 m m.group('quote') m.end('quote') (等) 傳遞到 re.sub() 裏的 repl 參數中 g<quote> g<1> 1
- (?P=name)
反向引用一個命名組合;它匹配前面那個叫 name 的命名組中匹配到的串一樣的字串。
- (?#…)
註釋;裏面的內容會被忽略。
- (?=…)
匹配 … 的內容,可是並不消費樣式的內容。這個叫作 lookahead assertion。好比, Isaac (?=Asimov) 匹配 'Isaac ' 只有在後面是 'Asimov' 的時候。
- (?!…)
匹配 … 不符合的狀況。這個叫 negative lookahead assertion (前視取反)。好比說, Isaac (?!Asimov) 只有後面 不 是 'Asimov' 的時候才匹配 'Isaac ' 。
- (?<=…)
匹配字符串的當前位置,它的前面匹配 … 的內容到當前位置。這叫:dfn:positive lookbehind assertion (正向後視判定)。 (?<=abc)def 會在 'abcdef' 中找到一個匹配,由於後視會日後看3個字符並檢查是否包含匹配的樣式。包含的匹配樣式必須是定長的,意思就是 abc 或 a|b 是容許的,可是 a* 和 a{3,4} 不能夠。注意以 positive lookbehind assertions 開始的樣式,如 (?<=abc)def ,並非從 a 開始搜索,而是從 d 往回看的。你可能更加願意使用 search() 函數,而不是 match() 函數: >>> import re >>> m = re.search('(?<=abc)def', 'abcdef') >>> m.group(0) 'def' 這個例子搜索一個跟隨在連字符後的單詞: >>> m = re.search(r'(?<=-)w+', 'spam-egg') >>> m.group(0) 'egg' 在 3.5 版更改: 添加定長組合引用的支持。
- (?<!…)
匹配當前位置以前不是 … 的樣式。這個叫:dfn:negative lookbehind assertion (後視判定取非)。相似正向後視判定,包含的樣式匹配必須是定長的。由 negative lookbehind assertion 開始的樣式能夠從字符串搜索開始的位置進行匹配。
- (?(id/name)yes-pattern|no-pattern)
若是給定的 id 或 name 存在,將會嘗試匹配 yes-pattern ,不然就嘗試匹配 no-pattern,no-pattern 可選,也能夠被忽略。好比, (<)?(w+@w+(?:.w+)+)(?(1)>|$) 是一個email樣式匹配,將匹配 '<user@host.com>' 或 'user@host.com' ,但不會匹配 '<user@host.com' ,也不會匹配 'user@host.com>'。
由 '' 和一個字符組成的特殊序列在如下列出。 若是普通字符不是ASCII數位或者ASCII字母,那麼正則樣式將匹配第二個字符。好比,$ 匹配字符 '$'.
- number
匹配數字表明的組合。每一個括號是一個組合,組合從1開始編號。好比 (.+) 1 匹配 'the the' 或者 '55 55', 但不會匹配 'thethe' (注意組合後面的空格)。這個特殊序列只能用於匹配前面99個組合。若是 number 的第一個數位是0, 或者 number 是三個八進制數,它將不會被看做是一個組合,而是八進制的數字值。在 '[' 和 ']' 字符集合內,任何數字轉義都被看做是字符。
- A
只匹配字符串開始。
- b
匹配空字符串,但只在單詞開始或結尾的位置。一個單詞被定義爲一個單詞字符的序列。注意,一般 b 定義爲 w 和 W 字符之間,或者 w 和字符串開始/結尾的邊界, 意思就是 r'bfoob' 匹配 'foo', 'foo.', '(foo)', 'bar foo baz' 但不匹配 'foobar' 或者 'foo3'。 默認狀況下,Unicode字母和數字是在Unicode樣式中使用的,可是能夠用 ASCII 標記來更改。若是 LOCALE 標記被設置的話,詞的邊界是由當前語言區域設置決定的,b 表示退格字符,以便與Python字符串文本兼容。
- B
匹配空字符串,但 不 能在詞的開頭或者結尾。意思就是 r'pyB' 匹配 'python', 'py3', 'py2', 但不匹配 'py', 'py.', 或者 'py!'. B 是 b 的取非,因此Unicode樣式的詞語是由Unicode字母,數字或下劃線構成的,雖然能夠用 ASCII 標誌來改變。若是使用了 LOCALE 標誌,則詞的邊界由當前語言區域設置。
- d
對於 Unicode (str) 樣式: 匹配任何Unicode十進制數(就是在Unicode字符目錄[Nd]裏的字符)。這包括了 [0-9] ,和不少其餘的數字字符。若是設置了 ASCII 標誌,就只匹配 [0-9] 。 對於8位(bytes)樣式: 匹配任何十進制數,就是 [0-9]。
- D
匹配任何非十進制數字的字符。就是 d 取非。 若是設置了 ASCII 標誌,就至關於 。
- s
對於 Unicode (str) 樣式: 匹配任何Unicode空白字符(包括 [ tnrfv] ,還有不少其餘字符,好比不一樣語言排版規則約定的不換行空格)。若是 ASCII 被設置,就只匹配 [ tnrfv] 。 對於8位(bytes)樣式: 匹配ASCII中的空白字符,就是 [ tnrfv] 。
- S
匹配任何非空白字符。就是 s 取非。若是設置了 ASCII 標誌,就至關於 。
- w
對於 Unicode (str) 樣式: 匹配Unicode詞語的字符,包含了能夠構成詞語的絕大部分字符,也包括數字和下劃線。若是設置了 ASCII 標誌,就只匹配 [a-zA-Z0-9_] 。 對於8位(bytes)樣式: 匹配ASCII字符中的數字和字母和下劃線,就是 [a-zA-Z0-9_] 。若是設置了 LOCALE 標記,就匹配當前語言區域的數字和字母和下劃線。
- W
匹配任何非詞語字符。是 w 取非。若是設置了 ASCII 標記,就至關於 。若是設置了 LOCALE 標誌,就匹配當前語言區域的 非 詞語字符。
- Z
只匹配字符串尾。
絕大部分Python的標準轉義字符也被正則表達式分析器支持。:
\a \b \f \n
\r \t \u \U
\v \x \\
(注意 b 被用於表示詞語的邊界,它只在字符集合內表示退格,好比 [b] 。)
'u' 和 'U' 轉義序列只在 Unicode 樣式中支持。 在 bytes 算啊看會顯示錯誤。 未知的 ASCII 字符轉義序列保留在將來使用,會被看成錯誤來處理。
八進制轉義包含爲一個有限形式。若是首位數字是 0, 或者有三個八進制數位,那麼就認爲它是八進制轉義。其餘的狀況,就看做是組引用。對於字符串文本,八進制轉義最多有三個數位長。
- 5
- ^
- 0-9
- tnrfv
- a-zA-Z0-9_