用Shell通配符比對字元串
問題
你想使用 Unix Shell 中常用的通配符(比如
*.py
,
Dat[0-9]*.csv
等)去比對文本字元串
解決方案
fnmatch
子產品提供了兩個函數——
fnmatch()
和
fnmatchcase()
,可以用來實作這樣的比對。用法如下:
>>> from fnmatch import fnmatch, fnmatchcase
>>> fnmatch('foo.txt', '*.txt')
True
>>> fnmatch('foo.txt', '?oo.txt')
True
>>> fnmatch('Dat45.csv', 'Dat[0-9]*')
True
>>> names = ['Dat1.csv', 'Dat2.csv', 'config.ini', 'foo.py']
>>> [name for name in names if fnmatch(name, 'Dat*.csv')]
['Dat1.csv', 'Dat2.csv']
>>>
fnmatch()
函數使用底層作業系統的大小寫敏感規則(不同的系統是不一樣的)來比對模式。比如:
>>> # On OS X (Mac)
>>> fnmatch('foo.txt', '*.TXT')
False
>>> # On Windows
>>> fnmatch('foo.txt', '*.TXT')
True
>>>
如果你對這個差別很在意,可以使用
fnmatchcase()
來代替。它完全使用你的模式大小寫比對。比如:
>>> fnmatchcase('foo.txt', '*.TXT')
False
>>>
這兩個函數通常會被忽略的一個特性是在處理非檔案名的字元串時候它們也是很有用的。 比如,假設你有一個街道位址的清單資料:
addresses = [
'5412 N CLARK ST',
'1060 W ADDISON ST',
'1039 W GRANVILLE AVE',
'2122 N CLARK ST',
'4802 N BROADWAY',
]
你可以像這樣寫清單推導:
>>> from fnmatch import fnmatchcase
>>> [addr for addr in addresses if fnmatchcase(addr, '* ST')]
['5412 N CLARK ST', '1060 W ADDISON ST', '2122 N CLARK ST']
>>> [addr for addr in addresses if fnmatchcase(addr, '54[0-9][0-9] *CLARK*')]
['5412 N CLARK ST']
>>>
讨論
fnmatch()
函數比對能力介于簡單的字元串方法和強大的正規表達式之間。 如果在資料處理操作中隻需要簡單的通配符就能完成的時候,這通常是一個比較合理的方案。
如果你的代碼需要做檔案名的比對,最好使用
glob
子產品