我的目录中的文件格式如下:LnLnnnnLnnn.txt
其中L =字母,n =数字。例如:p2c0789c001.txt
我想根据第二个数字(即0789)是奇数还是偶数来分隔这些文件。
如果第二个数字的范围介于0001-0009之间,我只能设法使用此代码:
odd_files = []
for root, dirs, filenames in os.walk('.'):
for filename in fnmatch.filter(filenames, 'p2c000[13579]*.txt'):
odd_files.append(os.path.join(root, filename))
这将返回文件:['./p2c0001c054.txt', './p2c0003c055.txt', './p2c0005c056.txt', './p2c0007c057.txt', './p2c0009c058.txt']
任何建议我如何才能让任何给定的四位数字工作?
答案 0 :(得分:1)
会这样做吗?
import re
regex = re.compile("[a-z][0-9][a-z]([0-9]{4})[a-z][0-9]{3}.txt")
filter(lambda x: int(regex.match(x).groups()[0]) % 2 == 1, fnmatch)
答案 1 :(得分:1)
如果它有点毛茸茸的话,你可以随时把它变成发电机并手工编写测试代码:
def odd_files_generator():
for root, dirs, filenames in os.walk('.'):
for filename in filenames:
if filename[6] in '13579':
yield filename
odd_files = list(odd_files_generator)
如果您的测试变得非常难以表达,请将if filename ...
行替换为您明确的测试代码。
答案 2 :(得分:1)
最简单的解决方案是扩展您的通配符以匹配更多内容。
为此,我可能会做类似的事情:for filename in fnmatch.filter(filenames, '??????[13579]*.txt'):
这将匹配您的值之前的任何字符,它将匹配您的通配符类中的任何奇数值,然后它将接受任何匹配的事后。
这有点严重,因为它是aaaaaaa3alkjfdhalkjfshglkjzsdhfgs.txt匹配,这是超级粗略。如果您知道您正在行走的目录中的数据得到很好的控制,那可能就行了。更好的解决方案可能是更多地指定一些东西。这可以通过以下表达式完成:
'[a-z][0-0][a-z][0-9][0-9][0-9][13579][a-z][0-9][0-9][0-9].txt'
使用Unix样式通配符的fnmatch.filter方法。这意味着您可以使用以下内容:
? - 匹配任何单个字符 * - 从无到有,无所不能 [] - 这匹配一类东西,使用 - 为范围和!排除
答案 3 :(得分:1)
构建这种过滤器没有特别的魔力。它只是 需要仔细构建适当的正则表达式和测试 反对。当使用具有大量重复组件的复杂模式时, 错误很容易蔓延。我喜欢定义辅助功能 如果需要,规范更易于人工阅读并且更容易修改。
import re
import os
# helper functions for legible re construction
LETTER = lambda n='': '({0}{1})'.format('[A-Za-z]', n)
NUM = lambda n='': '({0}{1})'.format('\d', n)
FILENAME = LETTER() + NUM() + LETTER() + NUM('{4}') + LETTER() + NUM('{3}') + '\.txt'
FILENAME_RE = re.compile(FILENAME)
is_odd = lambda n: int(n) % 2 > 0
def odd_nnnn(f):
"""
Determine if the given filename `f` matches our desired LnLnnnnLnnn.txt pattern
with the second group of numbers (nnnn) odd.
"""
m = FILENAME_RE.search(f)
return m is not None and is_odd(m.group(4))
if __name__ == '__main__':
print "Search pattern:", FILENAME
files = ['./p2c0001c054.txt', './p2c0001c055.txt', './p2c0003c055.txt', './p2c0005c056.txt', './p2c0022c056.txt', './p2c0004c056.txt', './p2c0007c057.txt', './p2c0009c058.txt', './p2c8888c056.txt', ]
files = [ os.path.normpath(f) for f in files ]
root = '/users/test/whatever'
odd_paths = [ os.path.join(root, f) for f in files if odd_nnnn(f) ]
print odd_paths
唯一真正的缺点是,它更加冗长,特别是与 Brad Beattie 等超紧凑的答案相比。
[更新]后来我发现定义正则表达式的更简洁方法可能是:
FILENAME = "LnL(nnnn)Lnnn\.txt"
FILENAME_PAT = FILENAME.replace('L', r'[A-Za-z]').replace('n', r'\d')
FILENAME_RE = re.compile(FILENAME_PAT)
这更接近原始的  LnLnnnLnnn.txt'描述。匹配表达式必须从m.group(4)
更改为m.group(1)
,因为只有一个组以这种方式捕获。