2.3 用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 模�。�考5.13�节。