搜索与列表中的任何字符串匹配的文件?

Search for files that match any strings from a list?

我想递归遍历一个目录,找到与给定列表中的 任意 字符串匹配的文件,然后将这些文件复制到另一个文件夹。我认为 any() 函数可以完成此操作,但我得到一个 TypeError,它需要一个字符串,而不是一个列表。有没有更优雅的方法来做到这一点?

string_to_match = ['apple.txt', 'pear.txt', 'banana.txt']

for root, subdirs, filename in os.walk(source_dir)
    if any(s in filename for s in string_to_match):
        shutil.copy(filename, destination_dir)
        print(filename)

我知道 glob.glob 可以很好地查找与特定字符串或模式匹配的文件,但我一直无法找到允许多个匹配的答案。

你可以直接使用in

示例:

string_to_match = ['apple.txt', 'pear.txt', 'banana.txt']

for root, subdirs, filename in os.walk(source_dir)
    if filename in string_to_match:
        shutil.copy(filename, destination_dir)
        print(filename)

这里还有一个 glob 版本:

import glob
import itertools

root_dir = '/home/user'
files = ['apple.txt', 'pear.txt', 'banana.txt']
files_found = list(itertools.chain.from_iterable([glob.glob(f'{root_dir}/**/{f}', recursive=True) for f in files])
for f in files_found:
     shutil.copy(f, destination_dir)  
    

首先,在列表中找到一个元素的时间复杂度为O(n),因此只需将其转换为一个时间复杂度为O(1)的集合即可。

那你可以这样做

string_to_match = {'apple.txt', 'pear.txt', 'banana.txt'}
for filename in os.listdir(source_dir):
    if filename in string_to_match:
        shutil.copy(filename, destination_dir)
        print(filename)

    

我会用套装

def find_names(names,source_dir):
    names = set(names)
    # note os.walk will walk the subfolders too
    # if you just want that source_dir use `strings_to_match.intersection(os.listdir(sourcedir))`
    for root,subdirs,fnames in os.walk(sourcedir):
       for matched_name in strings_to_match.intersection(fnames):
           yield os.path.join(root,matched_name)
    
strings_to_match = ['apple.txt', 'pear.txt', 'banana.txt']
for match in find_names(strings_to_match,'/path/to/start'):
   print("Match:", match)

[已编辑] 打字错误 intersection 不是 intersect

(您也可以只传入集合 {'a','b','c'} 而不是列表 ['a','b','c'] 并跳过到集合的转换)

这是一个只在源目录(而不是子目录)中查找的替代方法

def find_names_in_folder(names,source_dir):
    return [os.path.join(source_dir,n) for n in set(names).intersection(os.listdir(source_dir))]