目錄
- 問題
- 解決方案
- 討論
問題
在不同的操作系統下,怎樣做字符串匹配?
解決方案
fnmatch()
模塊提供兩個函數,fnmatch()
以及 fnmatchcase()
可以用來執行做這樣的匹配。
from fnmatch import fnmatch, fnmatchcasematch_res = fnmatch('foo.txt', '*.txt')
print(match_res)
match_res2 = fnmatch('foo.txt', '?oo.txt')
match_res3 = fnmatch('foo.txt', '?oo.txt')
match_res4 = fnmatch('Dat45.csv', 'Dat[0-9]*')
match_res5 = fnmatch('Dat45.csv', 'Dat[0-9].csv')
match_res6 = fnmatch('Dat45.csv', 'Dat[0-9][0-9].csv')print(match_res2, match_res3, match_res4, match_res5, match_res6)
結果:
True True True False True
fnmatch()
函數也可以處理更多復雜場景的數據結構:
names = ['Dat1.csv', 'Dat2.csv', 'config.ini', 'foo.py', 'api.py']
matchs = [name for name in names if fnmatch(name, 'Dat*.csv')]
print(matchs)
結果:
['Dat1.csv', 'Dat2.csv']
一般來說,在不同的操作系統上,fnmatch()
的匹配模式所采用的大小寫區分規則和底層文件系統相同,即根據操作系統的不同而有所不同。例如:
# On OS X (MAX)
fnmatch('foo.txt', '*.TXT')
>>> False# On Windows
fnmatch('foo.txt', '*.TXT')
>>> True
但是如果大小寫統一化很重要,那么我們除了使用 lower()
等方法統一化字符串大小寫以外,還可以通過 fnmatchcase()
方法,完全根據我們提供的大小寫方式來進行匹配。
fnmatch_res = fnmatch('foo.txt', '*.TXT')
fnmatchcase_res = fnmatchcase('foo.txt', '*.TXT')
print('fnmatch_res :', fnmatch_res)
print('fnmatchcase_res :', fnmatchcase_res)
結果:
討論
fnmatch
模塊的兩個函數其實在處理非文件名式的字符串時有非常大的潛在用途:
addresses = ['5412 N CLARK ST','1060 W ADDISON ST','1039 W GRANVILLE AVE','2122 N CLARK ST','4902 N BROADWAY'
]address_res1 = [addr for addr in addresses if fnmatchcase(addr, '*ST')]
print(address_res1)
address_res2 = [addr for addr in addresses if fnmatchcase(addr, '54[0-9][0-9] *CLARK*')]
print(address_res2)
結果:
['5412 N CLARK ST', '1060 W ADDISON ST', '2122 N CLARK ST']
['5412 N CLARK ST']
小結:
fnmatch
所完成的匹配操作有點介乎于簡單的字符串方法和全功能的正則表達式之間。但是如果只是試著在處理數據時提供一種簡單的機制以允許使用通配符,那么字符串方法,fnmatch
都是合理的解決方案。
但是如果實際上想編寫匹配文件名的代碼,glob 模塊似乎是一個更好的選擇。