2.Python3标准库--文本
生活随笔
收集整理的這篇文章主要介紹了
2.Python3标准库--文本
小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
(一)string:文本常量和模板
1.函數
import string ''' string模塊在最早的Python版本中就已經有了。以前這個模塊中提供的很多函數已經移植到str對象中,不過這個模塊仍然保留了很多有用的常量和類來處理str對象 '''# 函數capwords會把一個字符串中的所有單詞的首字母變成大寫 s = "when i was young, i'd listen to the radio" print(s) # when i was young, i'd listen to the radio print(string.capwords(s, sep=" ")) # When I Was Young, I'd Listen To The Radio # 這段代碼的結果等同于先調用split,把結果中的單詞首字母大寫,然后調用join來合并結果。sep可以省略,默認為空格
2.模板
?
import string''' 字符串模板是PEP292當中新增的部分,將作為內置拼接語法的替代做法。使用string.Template拼接變量時,要在名字前加前綴$來標識變量(例如$var)。 或者,如果有必要區分變量和周圍的文本,可以使用大括號包圍變量,如${var} ''' # 先看看str.format這種常規做法 values = {"var": "foo"} s = "var: %(var)s, escape: %%, %(var)sxxx" print("result ->", s % values) # result -> var: foo, escape: %, fooxxx # 注意到中間的escape: %%,這種觸發字符要想讓其失去效果,只當做普通字符來處理的話,要重復兩次來進行轉義# 下面來使用模板,可以看到最后一個var加上了{},因為var和后面的文本黏在一起了 s = "var: $var, escape: $$, ${var}xxx" # 第一步:先得到可以用來渲染的模板 t = string.Template(s) # 第二步:進行替換,會有一個返回值,就是我們替換之后的結果 print(t.substitute(values)) # var: foo, escape: $, fooxxx print(t.substitute(**values)) # var: foo, escape: $, fooxxx # 可以看到var都被替換成了foo。但是注意到我們傳入value(一個字典),和**value(var=foo關鍵字參數)得到的結果是一樣的。 # 因為string的模板不像flask,tornado等框架的模板一樣,支持邏輯上的運算或者數據結構上的變換。 # 如果在jinja2中,我傳入字典的話,那么在模板中還可以進行取值,但是string中的模板不支持,只支持字符間的替換。# 我們來看看jinja2 import jinja2 s = "{{var}}--{{dic.get('key', 'value')}}--{{dic.get('KEY', 'value')}}" t = jinja2.Template(s) print(t.render(var="foo", dic={"key": "mashiro"})) # foo--mashiro--value # 可以看到jinja2是支持字典的取值,由于dic中沒有"KEY"這個鍵,那么獲取默認值。但是string.Template是不支持的。 # 因此對于string.Template來說,傳入關鍵字參數和字典是一樣的,傳入字典會自動將字典給打開,根據k,v進行替換# 此外對于字符串的模板還有一個安全的用法 s = "$var--$missing" t = string.Template(s) # 我這里沒有傳入missing,因此如果使用substitute則會報錯,但如果是safe_substitute的話會自動忽略,只對傳入的進行替換 # 那如果我多穿了一個,比如說s中并沒有$xxx,那么會怎么樣呢? print(t.safe_substitute(var="foo", xxx="xxxxx")) # foo--$missing # 顯然沒有任何問題,因此可以總結一下 # s中定義了,但是模板替換的時候沒有傳相應的值,那么substitute會報錯,safe_substitute不會 # 但是s中沒有定義,比如$xxx,而我們卻多傳了,那么substitute和safe_substitute都不會報錯,會自動忽略
3.高級模板
?
''' 可以調整string.Template在模板中查找變量名所使用的正則表達式模式,以改變它的默認語法。 我們可以修改delimiter和idpattern屬性。 因此最簡單的方法就是自己定義一個類,繼承自string.Template,然后重寫這兩個屬性。 但是說實話,這個不常用,因此不再詳細介紹。 '''
4.Formatter
''' string.Formatter類實現了與str的format()方法相同的布局規范。 特性包括類型強制轉換,對齊,屬性,和域引用,命名和位置模板參數以及類型特定的格式化選項。 大部分情況下,使用format()已經足夠,而且會更加方便,但也可以通過Formatter構建子類,實現更復雜的效果(基本不用) '''
5.常量
import string''' string模塊包括大量與ASCII和數值字符集相關的常量,都可以通過string這個模塊直接獲取whitespace = ' \t\n\r\v\f' ascii_lowercase = 'abcdefghijklmnopqrstuvwxyz' ascii_uppercase = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' ascii_letters = ascii_lowercase + ascii_uppercase digits = '0123456789' hexdigits = digits + 'abcdef' + 'ABCDEF' octdigits = '01234567' punctuation = r"""!"#$%&'()*+,-./:;<=>?@[\]^_`{|}~""" printable = digits + ascii_letters + punctuation + whitespace '''
?
(二)textwrap:格式化文本段落
1.示例數據
?
import textwrap''' 需要美觀打印(pretty-printing)的情況下,可以使用textwrap模塊格式化要輸出的文本。 它提供了很多文本編輯器和字符處理器中都有的段落自動換行或填充特性 ''' text = '''There are moments in life when you miss someone so much that you just want to pick them from your dreams and hug them for real! Dream what you want to dream;go where you want to go;be what you want to be,because you have only one life and one chance to do all the things you want to do. '''?
2.填充段落
?
import textwraptext = '''There are moments in life when you miss someone so much that you just want to pick them from your dreams and hug them for real! Dream what you want to dream;go where you want to go;be what you want to be,because you have only one life and one chance to do all the things you want to do. ''' # fill函數取文本作為輸入,生成格式化文本作為輸出 print(textwrap.fill(text, width=50)) '''There are moments in life when you miss someone so much that you just want to pick them from your dreams and hug them for real! Dream what you want to dream;go where you want to go; be what you want to be,because you have only one life and one chance to do all the things you want to do. '''# 結果不是太讓人滿意。文本雖然已經對齊,不過只有第一行保留了縮進,后面各行的空格則嵌入在段落中?
3.去除現有的縮進
import textwraptext = '''There are moments in life when you miss someone so much that you just want to pick them from your dreams and hug them for real! Dream what you want to dream;go where you want to go;be what you want to be,because you have only one life and one chance to do all the things you want to do. '''# 關于剛才的例子,其輸出中混合嵌入了制表符和額外的空格,所以格式不是太美觀。 # 用dedent可以去除示例文本中所有的行前面的空白符,這會生成更好的結果 # 并且允許在Python代碼中直接使用docstring或者內嵌的多行字符串,同時去除代碼本身的格式。 print(textwrap.dedent(text).strip()) ''' There are moments in life when you miss someone so much that you just want to pick them from your dreams and hug them for real! Dream what you want to dream;go where you want to go; be what you want to be,because you have only one life and one chance to do all the things you want to do. ''' # 可以看到dedent作用就是把每一行開頭的縮進給去掉
4.結合dedent和fill
import textwraptext = '''There are moments in life when you miss someone so much that you just want to pick them from your dreams and hug them for real! Dream what you want to dream;go where you want to go;be what you want to be,because you have only one life and one chance to do all the things you want to do. '''dedent_text = textwrap.dedent(text).strip() print(textwrap.fill(dedent_text, width=60)) ''' There are moments in life when you miss someone so much that you just want to pick them from your dreams and hug them for real! Dream what you want to dream;go where you want to go; be what you want to be,because you have only one life and one chance to do all the things you want to do. '''
5.縮進塊
import textwraptext = '''There are moments in life when you miss someone so much that you just want to pick them from your dreams and hug them for real! Dream what you want to dream;go where you want to go;be what you want to be,because you have only one life and one chance to do all the things you want to do. ''' # 可以使用indent函數為一個字符串的所有行增加一致的前綴文本 dedent_text = textwrap.dedent(text).strip() final_text = textwrap.indent(dedent_text, ">>>") print(final_text) ''' >>>There are moments in life when you miss someone >>>so much that you just want to pick them >>>from your dreams and hug them for real! Dream what >>>you want to dream;go where you want to go; >>>be what you want to be,because you have >>>only one life and one chance to do all the things you want to do. '''# 除此之外還可以給指定行添加 final_text = textwrap.indent(dedent_text, prefix="->", predicate=lambda line: len(line.strip()) > 40) print(final_text) ''' ->There are moments in life when you miss someone so much that you just want to pick them ->from your dreams and hug them for real! Dream what ->you want to dream;go where you want to go; be what you want to be,because you have ->only one life and one chance to do all the things you want to do. ''' # 顯然lambda里面的line就是每一行的文本,指定文本長度大于40的
6.懸掛縮進
import textwraptext = '''There are moments in life when you miss someone so much that you just want to pick them from your dreams and hug them for real! Dream what you want to dream;go where you want to go;be what you want to be,because you have only one life and one chance to do all the things you want to do. ''' # 不僅可以設置輸出的寬度,還可以采用同樣的方式單獨控制首行的縮進,使首行的縮進不同于后續的各行 dedent_text = textwrap.dedent(text).strip() print(textwrap.fill(dedent_text,initial_indent="",subsequent_indent=" "*4,width=50)) ''' There are moments in life when you miss someoneso much that you just want to pick them fromyour dreams and hug them for real! Dream whatyou want to dream;go where you want to go; bewhat you want to be,because you have only onelife and one chance to do all the things youwant to do. ''' # 這便可以生成懸掛縮進,即首行縮進小于其他行的縮進 # 縮進值也可以包含非空白字符。 print(textwrap.fill(dedent_text,initial_indent="",subsequent_indent="*"*4,width=50)) ''' There are moments in life when you miss someone ****so much that you just want to pick them from ****your dreams and hug them for real! Dream what ****you want to dream;go where you want to go; be ****what you want to be,because you have only one ****life and one chance to do all the things you ****want to do. '''
7.截斷長文本
import textwraptext = '''There are moments in life when you miss someone so much that you just want to pick them from your dreams and hug them for real! Dream what you want to dream;go where you want to go;be what you want to be,because you have only one life and one chance to do all the things you want to do. ''' dedent_text = textwrap.dedent(text).strip() print(textwrap.shorten(dedent_text, width=50)) # There are moments in life when you miss [...]
(三)re:正則表達式
?1.查找文本中的模式
import re''' 正則表達式是一種用形式化語法描述的文本匹配模式,可以進行復雜的字符串匹配。 Python中的正則表達式通過re模塊提供,功能比Python內置的str更強,但是速度沒有str提供的方法快。 因此如果內置的str方法可以解決,那么直接用就可以。如果不好解決,再使用正則。 '''''' re最常見的方法就是搜索文本中的模式。match和search函數接收pattern(模式)和text(文本)作為輸入,找到這個模式時,就返回一個Match對象。 如果沒有找到模式,則返回None。 每個Match對象包含有關匹配性質的信息,包括原輸入字符串,所使用的正則表達式,以及模式在原字符串中出現的位置。 ''' pattern = "this" text = "你知道this的含義嗎?" match = re.search(pattern, text) print(match) # <re.Match object; span=(3, 7), match='this'> print(match.start()) # 3 print(match.end()) # 7 print(text[match.start(): match.end()]) # this# 以上是search,那么match呢? match = re.match(pattern, text) print(match) # None # 返回結果為None,match和search比較類似,但match只能從頭匹配查找, 而search可以在字符串的任意位置匹配查找。# 即使有多個滿足條件的也只會返回第一個。 print(re.search("this", "123this456this789this")) # <re.Match object; span=(3, 7), match='this'># 如果沒有則返回None,此時調用下面的start或end方法也會報錯。會拋出AttributeError: 'NoneType' object has no attribute 'xxxxxx' # 因此可以加上一層判斷 match = re.match(pattern, text) if match:print(match.start())
2.編譯表達式
import re''' 我們也可以將模式進行一個編譯,比如我們有很多手機號,但我只查詢以135開頭的。 按照我們剛才講的,可以這么做。 for number in number_list:if re.match("135", number):print(number) 這么做毫無疑問是可行的,但是我們每循環一次,pattern都要編譯一次。既然pattern是固定不變的,我們是不是可以提前將它編譯好呢? 答案是可以的 ''' # 得到編譯之后的對象 comp = re.compile("135") # 下面就可以直接使用這個編譯的對象進行查找就可以了 number_list = ["13541258742", "18845214415", "13512441552"] for number in number_list:# 可以看到,如果使用re的話,需要傳入pattern,但是我們將pattern進行編譯之后,就可以直接調用了。if comp.match(number):print(number)'''1354125874213512441552'''''' re.match(pattern, text) <==> re.compile(pattern).match(text) ''' # 可以對比字符串,準確的說應該對比成類與對象 s = "abc|abcd|efg" print(s.split("|")) # ['abc', 'abcd', 'efg'] # 也可以使用str這個類來調用,但是不方便,于是我們都使用字符串本身,也就是類str的實例對象 print(str.split(s, "|")) # ['abc', 'abcd', 'efg']# summary:可以傳入pattern和text作為參數,調用re.match,也可以將pattern編譯之后,用編譯之后的對象調用match方法,此時只需傳入text
3.多重匹配
?
import re''' 到目前為止,我們所獲取的都是單個實例。如何將滿足條件的所有文本全部獲取呢? 可以使用findall函數 ''' pattern = "abc" text = "abc|abc|abc|abc" print(re.findall(pattern, text)) # ['abc', 'abc', 'abc', 'abc'] # 可以看到,直接將滿足條件的所有實例全部以列表的形式獲取出來了,并且如果滿足條件的實例只有一個,那么得到的仍是一個列表,只是列表里面只有一個元素# 除此之外還有一個迭代器模式 res = re.finditer(pattern, text) print(res) # <callable_iterator object at 0x00000000029C4400> for v in res:print(v)'''<re.Match object; span=(0, 3), match='abc'><re.Match object; span=(4, 7), match='abc'><re.Match object; span=(8, 11), match='abc'><re.Match object; span=(12, 15), match='abc'>'''# 得到的是一個Match對象?
4.模式語法
import re''' 除了簡單的字面量文本字符串,正則表達式還支持更強大的模式。 ''' # 重復 ''' .:代表除換行符之外的任意字符 *:重復0次或者任意多次 +:重復1次或者任意多次 ?:重復0次或者1次 {m}:出現m次 {m,n}:出現m次到n次,包含m和n,并且注意,逗號兩邊不要有空格 {m,}:省略n,那么表示至少出現m次,最多則沒有限制因此:* == {0,} + == {1,} ? == {0,1} '''# b出現一次到三次,注意這里不是ab出現一到三次,*+?{}只會作用于它的前一個字符 print(re.search("ab{1,3}", "abcabbc")) # <re.Match object; span=(0, 2), match='ab'> print(re.search("ab{2,3}", "abcabbc")) # <re.Match object; span=(3, 6), match='abb'> ''' 可以看到都是從頭開始找,開頭是ab滿足"ab{1,3}",即使后面有abb也不會匹配了 而"ab{2,3}"則要求b至少出現兩次,因此找到了后面的abb '''# 可以看到,要求是一到三次,ab,abb,abbb都符合,最終是取了abbb。 # 正則的模式則是貪婪模式,能往多了匹配就往多了匹配 print(re.search("ab{1,3}", "abbbbb")) # <re.Match object; span=(0, 4), match='abbb'># *+?這些元字符也是同樣的道理 print(re.search("ab*", "abbbbb")) # <re.Match object; span=(0, 6), match='abbbbb'> print(re.search("ab+", "abbbbb")) # <re.Match object; span=(0, 6), match='abbbbb'> print(re.search("ab?", "abbbbb")) # <re.Match object; span=(0, 2), match='ab'># 那么如何不使用這種貪婪模式呢?可以直接在*+?{}后面加上?即可,表示關閉貪婪模式 # 出現一到三次,關閉貪婪,只獲取一個b print(re.search("ab{1,3}?", "abbbbb")) # <re.Match object; span=(0, 2), match='ab'> # *出現0次或多次,關閉貪婪模式,獲取0次 print(re.search("ab*?", "abbbbb")) # <re.Match object; span=(0, 1), match='a'> # 顯然獲取一次 print(re.search("ab+?", "abbbbb")) # <re.Match object; span=(0, 2), match='ab'> # 出現0次或一次,關閉貪婪模式后顯然獲取0次 print(re.search("ab??", "abbbbb")) # <re.Match object; span=(0, 1), match='a'> # .表示除了換行符的任意字符 print(re.search(".{1,5}", "aaaaa")) # <re.Match object; span=(0, 5), match='aaaaa'> print(re.search(".{1,5}", "aa\naa")) # <re.Match object; span=(0, 2), match='aa'># 字符集 ''' 下面問題又來了,如果我想獲取以a開頭以c結尾,中間的一個字符必須是love中的一個,想獲取這樣的字符該怎么辦呢? 首先兩端好解決,關鍵是中間的字符要怎么表示? 這個時候字符集就派上用場呢? [love]:用中括號把多個字符組合起來即可,表示匹配l、o、v、e四個字符中的一個 ''' print(re.findall("a[love]c", "awc|aec|afc|akc|adc")) # ['aec'] # 字符集[love]就可以看做是一個整體,也可以搭配元字符使用 ''' [love]{1,3} 表示匹配出現一到三次的字符,什么的字符呢?l、o、v、e四個字符當中的某一個字符 ''' # v在[love]當中,匹配vvv print(re.findall("[love]{1,3}", "vvv")) # ['vvv'] # k不在但是v在,匹配vv print(re.findall("[love]{1,3}", "kvv")) # ['vv'] # 匹配v print(re.findall("[love]{1,3}", "kv")) # ['v'] # a不在,但ve在,匹配ve print(re.findall("[love]{1,3}", "ave")) # ['ve'] # findall是查找所有,l在[love]里面,o在,v在,但是最多出現三次匹配成功結束。繼續查找,最后的e也在,但是_不在,所以匹配結束,得到e。 # y不在,但是o在,u又不在,所以又匹配出e。因此最終結果是['lov', 'e', 'o']。 print(re.findall("[love]{1,3}", "love_you")) # ['lov', 'e', 'o']# 那我如果想取反呢?也就是我要不在love里面的字符??梢允褂肹^love],表示非l、o、v、e的任意字符# 這便是字符集,但是又有一個問題。如果我想獲取為小寫字母的字符呢?難道把26的字母都寫一遍嗎?當然不用 # [a-z]表示所有的小寫字母 # [A-Z]表示所有的大寫字母 # [0-9]表示所有的數字 # [a-zA-Z0-9]表示所有的字母和數字 print(re.findall("[a-z][A-Z]", "aB|ac")) # ['aB'] print(re.findall("[a-zA-Z]", "a|C|4|尻")) # ['a', 'C'] print(re.findall("[a-zA-Z0-9]", "a|C|4|尻")) # ['a', 'C', '4']# 轉義碼 # \d表示數字 # \D表示非數字 # \w表示字母、數字,注意:這里包括中文 # \W表示非字母數字 # \s表示空白符(制表符、空格、換行等) # \S表示非空白符# 但是\在操作系統中會先做一層轉義,因此需要兩個\。在操作系統層面上,兩個\變成一個\,然后再和d組合成\d進行正則比配 print(re.search("\\d{1,3}", "1234")) # <re.Match object; span=(0, 3), match='123'> # 那如果我想匹配\呢? print(re.search("\\\\hello", "\\hello")) # <re.Match object; span=(0, 6), match='\\hello'> ''' 要知道\在正則中也是有含義的,因此要匹配純反斜杠,也需要做一次轉義。 所以需要四個\,首先在在操作系統層面會轉義,將四個\變成兩個\,在正則中兩個\變成一個\,此時的\便是普通的字符 但是這樣會很麻煩,因此可以在字符串的開頭加上一個r,表示這是原生的字符串,你不需要給我做任何的轉義 ''' # 此時只需要一個反斜杠即可,可以看到Python中的\w是包含中文的 print(re.search(r"\w{1,2}", "古明地覺")) # <re.Match object; span=(0, 2), match='古明'># 錨定 ''' 有時除了匹配模式的內容外,我們還要對內容的位置進行一個限制。 ^:這個符號我們剛才好像見過,[^seq],表示不在seq里面的字符,但是如果放在開頭的位置,則表示以某字符開頭,如^abc則表示以abc開頭的字符 $:表示以某字符結尾。如abc$表示以abc結尾的字符 \b:單詞開頭或末尾的空串 \B:不在單詞開頭或末尾的空串 ''' print(re.search(r"^abc", "abcd")) # <re.Match object; span=(0, 3), match='abc'> print(re.search(r"^abc", "aabcd")) # Noneprint(re.search(r"abc$", "dabc")) # <re.Match object; span=(1, 4), match='abc'> print(re.search(r"abc$", "abcd")) # None
5.限制搜索
import re''' 已經編譯的正則表達式,還可以指定查找的范圍 ''' pattern = re.compile(r"123") text = "123|123|123" print(pattern.search(text, pos=2, endpos=7)) # <re.Match object; span=(4, 7), match='123'> # 指定從2開始,7結束
6.用組解析匹配
import re''' 有時我們想要提取某些內容中間的內容,比如xxxabcxxx,我想要夾在xxx和xxx之間的內容怎么辦呢? 這個時候就可以用到分組 ''' # 有兩個abc,但我要的是夾在xxx和xxx之間的abc match = re.search(r"xxx(abc)xxx", "abcxxxabcxxx") print(match) # <re.Match object; span=(3, 12), match='xxxabcxxx'> # 這樣匹配依舊會匹配全局,怎么樣才能把括號里面的內容給抽取出來呢? print(match.group(0)) # xxxabcxxx print(match.group(1)) # abc ''' 可以使用group函數,參數默認是0,表示全局。 參數為1,表示第一個括號里面的內容,參數為n,表示第n個括號里面的內容 '''match = re.search(r"123(.+?)456(.+?)789", "123abc456def789") print(match.group(0)) # 123abc456def789 print(match.group(1)) # abc print(match.group(2)) # def# 那么問題來了,如果是這樣呢? match = re.search(r"123((.+?)456(.+?))789", "123abc456def789") print(match.group(0)) # 123abc456def789 print(match.group(1)) # abc456def print(match.group(2)) # abc print(match.group(3)) # def ''' 可以看到,我在(.+?)456(.+?)外層又加上了一層括號 分組的順序,是從左往右,找到了(,就會進行分組,至于),會自動進行匹配,所以group(1)是最外層的abc456def group(2)是456左邊的(.+?),group(3)是456右邊的(.+?) '''# 此外還可以給組進行命名。只需要在括號里面加上?P<name>即可,name是我們指定的分組的名字 match = re.search(r"123(?P<yoyoyo>.+?)456(?P<哈哈哈>.+?)789", "123納尼456我屮艸芔茻789") print(match.group("yoyoyo"), match.group("哈哈哈")) # 納尼 我屮艸芔茻 print(match.group(1), match.group(2)) # 納尼 我屮艸芔茻 # 并且使用組的序號依舊是可以的# 除了group之外,還可以使用groupdict和groups match = re.search(r"123(?P<yoyoyo>.+?)456(?P<哈哈哈>.+?)789", "123納尼456我屮艸芔茻789") print(match.groups()) # ('納尼', '我屮艸芔茻') print(match.groupdict()) # {'yoyoyo': '納尼', '哈哈哈': '我屮艸芔茻'}# groups無論是否指定組名,都會獲取到。但是groupdict只會獲取指定組名的分組,比如說: match = re.search(r"123(?P<yoyoyo>.+?)456(.+?)789", "123納尼456我屮艸芔茻789") print(match.groups()) # ('納尼', '我屮艸芔茻') # 可以看到沒有指定組名的就獲取不到了 print(match.groupdict()) # {'yoyoyo': '納尼'}# 此外在分組的時候,還可以指定管道符|,表示或者。比如 # jpg|png表示獲取的是jpg或者png,注意:管道符會作用于兩邊的全部字符,比如: # www.mashiro.jpg|png,則表示的是www.mashiro.jpg或者png # www.mashiro.(jpg|png),此時的管道符只會作用于括號里面兩端的字符,表示www.mashiro.jpg或者www.mashiro.png print(re.search(r"www\.mashiro\.(jpg|png)", "www.mashiro.jpg")) # <re.Match object; span=(0, 15), match='www.mashiro.jpg'> # 注意這里的\.表示轉義,讓.表示普通的. 不是具有匹配字符能力的.# 但是這里又出現問題了,比如說 text = '''這里有圖片哦www.1.jpg,有很多格式的哦www.2.png,想看嗎,還會動哦,www.3.gif那還等什么呢?www.banana.jpg,快去吧,那個象征自由的男人在等著你www.象征自由的男人--尻比.png ''' res = re.findall(r"www.+?(jpg|png|gif)", text) print(res) # ['jpg', 'png', 'gif', 'jpg', 'png'] ''' 可以看到findall獲取的自動是分組里面的內容,可我們要的是整體的鏈接啊。怎么辦呢?一種方法是我在外面也加上括號不就行了 '''res = re.findall(r"(www.+?(jpg|png|gif))", text) print(res) # [('www.1.jpg', 'jpg'), ('www.2.png', 'png'), ('www.3.gif', 'gif'), ('www.banana.jpg', 'jpg'), ('www.象征自由的男人--尻比.png', 'png')] # 可以看到最外層的分組也被我們所捕獲了,多個分組的內容回族和成一個元組。因此可以使用索引獲取鏈接,但這還不是最完美的方法。 # 有什么辦法,讓里面的那個分組失去效果呢?就是說,我給你加上括號只是為了多匹配一些格式罷了,你就不要自作聰明地當做分組來處理了 # 答案是有的,只需要加上?:即可,在括號里面加上?:表示讓分組失去效果,也就是不表示分組 res = re.findall(r"www.+?(?:jpg|png|gif)", text) print(res) # ['www.1.jpg', 'www.2.png', 'www.3.gif', 'www.banana.jpg', 'www.象征自由的男人--尻比.png'] # 可以看到匹配成功,而且此時最外層也不需要再加上括號了,因為里面的分組失去效果了,相當于就沒有分組了,如果沒有分組,那么默認匹配整體。# 最后插一句,聊一聊www.+?(?:jpg|png|gif),為什么要是.+?呢,如果是.+行不行,比如: print(re.search(r"www.+?jpg", "www.1.jpg我屮艸芔茻www.2.jpg").group()) # www.1.jpg # 我把?去掉,那么等于變成了貪婪模式。 print(re.search(r"www.+jpg", "www.1.jpg我屮艸芔茻www.2.jpg").group()) # www.1.jpg我屮艸芔茻www.2.jpg # 那么會從第一個www開始,匹配到最后一個jpg,因此要注意開啟非貪婪模式
7.搜索選項
?
import re''' 選項標志是用來改變匹配引擎處理表達式的方式。 比如說,我們可以看看re.search()的函數原型 def search(pattern, string, flags=0): 這個pattern和string我們都知道,但是最后一個參數flags是什么鬼? 這個flags就是選項標志,也是我們接下來要說的內容 '''# 大小寫無關 ''' 有些時候,我們不想區分大小寫該怎么辦呢?比如說aa和AA我們認為都是合法的。 ''' # 這便是flags的作用,可以用來改變引擎處理表達式的方式 # re.IGNORECASE表示忽略大小寫敏感模式,其中re.IGNORECASE也可以寫成re.I match = re.match(r"aa", "aA", flags=re.IGNORECASE) print(match) # <re.Match object; span=(0, 2), match='aA'># 多行輸入 ''' 有兩個標志會影響如何完成多行輸入的搜索:MULTILINE和DOTALL。 MULTILINE表示^和*的錨定規則除了應用于整個字符串之外,還對每一行的開頭和結尾起作用。(不常用) DOTALL表示.這個元字符可以匹配換行符,默認情況下,.這個元字符是不能匹配換行符的,但是加上這個參數之后,便可以匹配換行符注:re.MULTILINE可以寫成re.M,re.DOTALL可以寫成re.S ''' match = re.match(r".+", "aabb\ncc") print(match) # <re.Match object; span=(0, 4), match='aabb'> match = re.match(r".+", "aabb\ncc", flags=re.DOTALL) print(match) # <re.Match object; span=(0, 7), match='aabb\ncc'># Unicode ''' 默認情況下,正則表達式處理的都是Unicode文本,也就是說\w是可以匹配中文的。 如果我想只匹配ASCII碼呢?可以使用re.ASCII,這樣的話就不會匹配中文了. re.ASCII也可以寫成re.A ''' print(re.match(r"\w+", "love中國")) # <re.Match object; span=(0, 6), match='love中國'> print(re.match(r"\w+", "love中國", flags=re.ASCII)) # <re.Match object; span=(0, 4), match='love'>
8.字符串替換
import re''' 我們也可以將字符串進行一個替換 ''' text = "when i was young, i'd listen to the radio" # 我要把當中所有的i替換成大寫的I,怎么做呢? # 可以使用re.sub函數,def sub(pattern, repl, string, count=0, flags=0): # 參數:要替換的字符模式 替換成哪些字符 文本 替換的數量(默認為0,表示全部) 匹配模式 print(re.sub(r"i", "I", text)) # when I was young, I'd lIsten to the radIo# 我要把里面的英文全部刪除 text = "古明地覺(komeiji satori)是一個來自于東方地靈殿的女孩,它有一個妹妹,叫古明地戀(komeiji koishi)" # 把\w都替換成空即可,但是注意\w默認是匹配中文(以及日文等等)的,所以要加上flags=re.A,表示只匹配ASCII碼中的字符 print(re.sub(r"\w", "", text, flags=re.A)) # 古明地覺( )是一個來自于東方地靈殿的女孩,它有一個妹妹,叫古明地戀( ) # 不加flags的話,會把中文也剝掉了 print(re.sub(r"\w", "", text)) # ( ),,( )# 除此之外還有一個函數叫做subn,和sub一樣,但是除了返回替換的內容,還會返回替換的數量 print(re.subn("a", "b", "accaccacc")) # ('bccbccbcc', 3)
9.利用模式拆分
import re''' 類似于str.split,re也可以使用split函數,而且功能更加強大 ''' text = "abc1def55455ghi6621" # 我要按照數字切割,最終只保留,abc def ghi該怎么做呢? # 直接調用split即可, 此外還可以指定最多分割多少次,不指定默認為全部。這里表示用數字切割 print(re.split(r"\d", text)) # ['abc', 'def', '', '', '', '', 'ghi', '', '', '', ''] # 可以手動去掉空格 no_space = list(filter(lambda x: len(x), re.split(r"\d", text))) print(no_space) # ['abc', 'def', 'ghi']
(四)difflib:比較序列
import difflib''' difflib模塊包含一些計算和處理序列之間差異的工具。 它對于比較文本及其有用,其中的函數可以使用多種常用的差異格式生成報告 '''
1.比較文本體
import difflibtext1 = '''Half the people on our streets look as though life was a sorry business. It is hard to find a happy looking man or woman. xxx Worry is the cause of their woebegone appearance. Worry makes the wrinkles; worry cuts the deep, down-glancing lines on the face; worry is the worst disease of our modern times. ''' text2 = '''Half the people on our streets look as though life was a sorry business. It is hard to find a happy looking man or woman. Worry is the cause of their woebegone appearance. Worry makes the wrinkles; worry cuts the deep, down-glancing lines on the face; worry is the worst disease of our modern timeS. xxx xxx xxx xxx ''' # 將文本分解成由單個文本行構成的序列,與傳入大量字符串相比,會有更可讀的輸出 text1_lines = text1.splitlines() text2_lines = text2.splitlines()d = difflib.Differ() diff = d.compare(text1_lines, text2_lines) ''' differ類用于處理文本行序列,并生成可讀的差異(deltas)或更改指令,包括各行中的差異。 differ生成的默認輸出和Unix下的diff命令行工具類似,包括兩個列表的原始輸入值(包含共同的值),以及指示做了哪些更改的標記數據。*有-前綴的行在第一個序列中,而非第二個序列。*有+前綴的行在第二個序列中,而非第一個序列*如果某一行在不同版本之間存在增量差異,那么也會使用一個加?的前綴的額外行來強調新版本中的變更*如果一行未改變,則會打印輸出,而且左列有一個額外的空格,使它與其他可能有差異的輸出對齊 ''' # 得到的diff是一個生成器 print("\n".join(diff)) # 輸出結果如下 '''Half the people on our streets look as though life was a sorry business. - It is hard to find a happy looking man or woman. xxx ? ---+ It is hard to find a happy looking man or woman. Worry is the cause of their woebegone appearance. Worry makes the wrinkles; worry cuts the deep, down-glancing lines on the face; - worry is the worst disease of our modern times. ? ^+ worry is the worst disease of our modern timeS. ? ^+ xxx xxx xxx xxx ''' # 首先第一行是一樣的,直接打印 # 第二行,第一個序列,我故意在結尾多添了xxx,所以輸出已經用___進行了標記,并且開頭出現了?表示強調出現了變更,說白了我覺得就是為了做標記而單起一行 # 如果出現了差異,那么兩個序列都會打印出現差異的行,因此下面還會輸出一次,并且前綴是+,表示這是第二個序列 # 然后面下面兩個是沒有問題的,所以正常輸出 # 然后再下一行我故意將times替換成了timeS,因此出現差異。 # 最后一行我多添加了xxx xxx xxx xxx,也顯示了第二個序列多了這么些內容
2.尋找最長的相同子串
from difflib import SequenceMatchertext1 = "abcd" text2 = "bcde" s1 = SequenceMatcher(None, text1, text2) # 尋找最長匹配的字符,里面接收四個參數,分別為text1查找的起始位置和終止位置,text2查找的起始位置和終止位置 match = s1.find_longest_match(0, len(text1), 0, len(text2)) print(match) # Match(a=1, b=0, size=3) print(match.a, match.b, match.size) # 1 0 3 ''' a:第一個序列開始的索引位置 b:第二個序列開始的索引位置 size:序列的長度 ''' print(text1[match.a: match.a+match.size]) # bcd print(text2[match.b: match.b+match.size]) # bcdtext1 = "when i was young, i would listen to the radio" text2 = "when i was old, i will listen to the radio" s2 = SequenceMatcher(None, text1, text2) match = s2.find_longest_match(0, len(text1), 0, len(text2)) print(match) # Match(a=25, b=22, size=20)text1 = "abcdefkaaa" text2 = "abcdefkaaa" # 這里的第一個參數可以指定成一個匿名函數,這里表示當遇到k這個字符就停止掃描(包括k) # 如果不指定那么由于兩個序列一樣,會得到全部 s2 = SequenceMatcher(lambda x: x == "k", text1, text2) match = s2.find_longest_match(0, len(text1), 0, len(text2)) print(match) # Match(a=0, b=0, size=7)# 此外還可以計算兩個字符的相似程度 text1 = "我的夢想是開飛機" text2 = "我的夢想是開拖拉機" s3 = SequenceMatcher(None, text1, text2) print("%.2f" % s3.ratio()) # 0.82# 有點類似于一個庫fuzzywuzzy from fuzzywuzzy import fuzz p = fuzz.ratio("我的夢想是開飛機", "我的夢想是開拖拉機") print(p) # 82 p2 = fuzz.ratio("我有一只貓", "我有一只貓咪!!!") print(p2) # 71 p3 = fuzz.partial_ratio("我有一只貓", "我有一只貓咪!!!") # 可以看到partial_ratio是如果一方結束了,就不在匹配了,所以這里是100 print(p3) # 100
?
轉載于:https://www.cnblogs.com/traditional/p/10436500.html
總結
以上是生活随笔為你收集整理的2.Python3标准库--文本的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: AOJ-AHU-OJ-592 神奇的叶子
- 下一篇: python中计算排列组合的函数_Pyt