字符串(二)
更新信息
2018-11-21 添加字符串格式化方法
f-string
python3.6以上版本支持
最短匹配
考慮如下字符串:
In [1]: text1 = 'Computer says "no."'
目前假如我只想匹配到雙引號中的內容 no.
我可以利用正則這樣寫:
In [2]: import re
In [3]: sre = re.compile(r'\"(.*)\"')
In [4]: sre.findall(text1)
Out[4]: ['no.']
上面的正則模式和返回結果好像沒什么, 別急,看看下面的
In [5]: text2 = 'Computer says "no." Phone says "yes."'
In [6]: sre.findall(text2)
Out[6]: ['no." Phone says "yes.']
上面的情況顯然不是我們想要的,我們本來只想要 no.
和 yes.
因為這里的正則模式中使用了 *
, 在正則中它代表了貪婪, 會盡可能多的去匹配。
要解決這個問題,只需要在后面加上一個問號即可 ?
, 它代表了是非貪婪,會盡可能少的去匹配。
In [7]: sre2 = re.compile(r'\"(.*?)\"')
In [8]: sre2.findall(text2)
Out[8]: ['no.', 'yes.']
在一 個模式字符串中,點 (
.
) 匹配除了換行外的任何字符。然而,如果你將點 (.
) 號放在開始 與結束符 (比如引號) 之間的時候,那么匹配操作會查找符合模式的最長可能匹配。這樣通常會導致很多中間的,那些被開始與結束符所包含的文本被忽略掉,并最終被包含在匹配 結果字符串中返回。通過在*
或者+
這樣的操作符后面添加一個?
可以強制匹配算法 改成尋找最短的可能匹配。
多行匹配
假如你想用一個模式在整個文本中進行多行內容的匹配,你想如何辦到?
比如去匹配 JavaScript
中的多行注釋
In [15]: text3 = "/*我是單行注釋*/"
In [16]: text4 = """/*
...: 在 JavaScript 中我其實是
...: 實現多行注釋的
...: */"""
In [17]: sre3 = re.compile(r'/\*(.*?)\*/')
In [18]: sre3.findall(text3)
Out[18]: ['我是單行注釋']
In [19]: sre3.findall(text4)
Out[19]: []
注意:
findall()
方法中的分組,之后保留被分組捕獲的內容。
在這里最容易忽略的是點 (.
)是不能夠匹配到換行符的。
于是在這里需要加上對換行符的支持,re.DOTALL
可以辦到,它可以讓點 .
匹配到換行符在內的任意字符。可以把它傳給 re.compile()
函數的第二個參數。這個叫做正則的標志參數。
In [21]: sre4 = re.compile(r'/\*(.*?)\*/', re.DOTALL)
In [22]: sre4.findall(text3)
Out[22]: ['我是單行注釋']
In [23]: sre4.findall(text4)
Out[23]: ['\n在 JavaScript 中我也是\n實現多行注釋的\n']
刪除一些字符串中不想要的字符
大家都知道 strip()
函數可以去除字符串兩端的空白字符, 就像這樣:
In [25]: s = " shark xiguatian \n"
In [26]: s.strip()
Out[26]: 'shark xiguatian'
它也可以去除字符串兩端的其他字符
In [27]: s1 = "===shark xiguatian====="
In [28]: s1.strip('=')
Out[28]: 'shark xiguatian'
lstrip()
和 rstrip()
分別從左邊和右邊去除不需要的字符
In [29]: s2 = "===shark xiguatian*****"
In [30]: s2.lstrip('=')
Out[30]: 'shark xiguatian*****'
In [31]: s2.lstrip('=').rstrip('*')
Out[31]: 'shark xiguatian'
其實也不用這么麻煩,可以像下面這樣
In [33]: s2.strip('=*')
Out[33]: 'shark xiguatian'
假如想要去除的字符
是在整個字符串的中間,可以用 replace()
和 正則的 re.sub()
In [37]: s3 = ' hello world \n'
In [38]: s3.replace(' ', '')
Out[38]: 'helloworld\n'
In [39]: re.sub(r'[\s+|\n]', '', s3)
Out[39]: 'helloworld'
處理讓你凌亂的字符
假如你遇到了這些字符
需要清理
In [45]: s = 'py?th?o?n?\fis\tawesome\r\n'
In [46]: s
Out[46]: 'py?th?o?n?\x0cis\tawesome\r\n'
穩住! 我們能贏!
首先要創建一個映射表
In [56]: remap = {
...: ord('\f'): ' ',
...: ord('\t'): ' ',
...: ord('\r'): '' # 刪除
...: }
In [57]: tp_s = s.translate(remap)
In [58]: tp_s
Out[58]: 'py?th?o?n? is awesome\n'
先把 \f
\t
映射成空格,再把 \r
刪除
ord()
是 python 的內置函數,可以將字符裝換為 ASCII 的數值或者 Unicode 數值,當然給的參數不可超出 ASCII 或者 Unicode 的范圍,比如給個中文的字符就會拋出異常。
和它對應的還有chr()
最后再來處理怪怪的字符
In [60]: import unicodedata
In [61]: import sys
In [62]: cmb_chrs = dict.fromkeys(c for c in range(sys.maxunicode)
...: if unicodedata.combining(chr(c)))
In [63]: tp_s.translate(cmb_chrs)
Out[63]: 'python is awesome\n'
上面的例子中,通過使用 dict.fromkeys() 方法構造一個字典,每個 Unicode 和音 符作為鍵,對應的值全部為 None 。然后再 調用 translate 函數刪除所有重音符。同樣的技術也可以被用來刪除其他類型的字符
講一下,簡單的替換用 replace()
效率會更高,而 tanslate()
在進行更復雜映射的時候處理的更快。
對齊字符串
當我知道 format()
內置函數后, 我就立刻拋棄了字符串的 center()
, ljust()
和 rjust()
三個方法。
In [80]: format(text, '>20')
Out[80]: ' Hello world'
In [81]: format(text, '*>20')
Out[81]: '*********Hello world'
In [82]: format(text, '<20')
Out[82]: 'Hello world '
In [83]: format(text, '*^20')
Out[83]: '****Hello world*****'
In [84]: y = 3.1415926
In [85]: format(y, '.2f')
Out[85]: '3.14'
In [86]: format(y, '.2%')
Out[86]: '314.16%'
In [87]: format(y, '^10.2%')
Out[87]: ' 314.16% '
format()
太通用了, 你說是嗎?
合并字符串
你是否經常這樣做
In [90]: b = 'world'
In [91]: s = a + b
In [92]: s
Out[92]: 'Helloworld'
+
加號對應數量不多的字符串的拼接還是比較推薦的方法,比較簡潔。
假如你需要對多個字符串進行拼接,應該使用字符串的 join()
方法
In [94]: li = ['a', 'b','c','d','e']
In [95]: ''.join(li)
Out[95]: 'abcde'
看下面這種情況:
In [96]: info = ['xiguatian', 25, 100]
這里不能簡單的使用
join()
方法了, 因為字符串和整型不可以直接拼接,需要把里面的int
類型的對象裝換為字符串對象后再拼接。
可以利用生成器表達式,同時把它統一類型為 str
In [98]: '_'.join(str(w) for w in info)
Out[98]: 'xiguatian_25_100'
同時還需要盡量避免不必要的拼接操作, 比如
print(a + ':' + b + ':' + c) # 菜鳥
print(':'.join([a, b, c])) # 入行
print(a, b, c, sep=':') # 老鳥
最后,你需要進行 I/O 操作寫文件時,下面是我們需要注意的
# 適合兩個字符串都很小的情況
f.write(chunk1 + chunk2)
# 適合兩個字符串會是很大的情況
f.write(chunk1)
f.write(chunk2)
在 python3.6 版本中加入了 f-string
, 用法就是在含有變量的字符串前加個 f
標識,就可以實現字符串的格式化。
In[150]: import sys
In [151]: sys.version
Out[141]: '3.6.4 (default, Jan 6 2018, 19:08:25) \n[GCC 4.2.1 Compatible Apple LLVM 9.0.0 (clang-900.0.39.2)]'
In [152]: name = 'shark'
In [153]: f'My name is {name}'
Out[153]: 'My name is shark'