import os import re import argparse from typing import List def search_in_file(file_path: str, pattern: str, is_regex: bool = False) -> List[str]: """ 在单个文件中搜索指定内容(文本/正则) Args: file_path: 文件路径 pattern: 要搜索的文本或正则表达式 is_regex: 是否按正则表达式匹配(默认False,按普通文本匹配) Returns: 匹配的行列表(格式:"行号: 行内容") """ matched_lines = [] try: # 支持常见编码(utf-8/gbk),避免中文乱码 with open(file_path, 'r', encoding='utf-8', errors='ignore') as f: for line_num, line in enumerate(f, 1): # 正则匹配 / 普通文本包含匹配 if is_regex: if re.search(pattern, line): matched_lines.append(f"第{line_num}行: {line.strip()}") else: if pattern in line: matched_lines.append(f"第{line_num}行: {line.strip()}") except (PermissionError, IsADirectoryError): # 跳过无权限文件/误判为文件的文件夹 pass return matched_lines def search_in_directory(dir_path: str, pattern: str, is_regex: bool = False, extensions: List[str] = None) -> None: """ 遍历文件夹下指定后缀的文件,搜索指定内容 Args: dir_path: 文件夹路径 pattern: 要搜索的文本或正则表达式 is_regex: 是否按正则表达式匹配 extensions: 要筛选的文件后缀列表(如 ['.css', '.js']),None 表示匹配所有文件 """ # 校验文件夹路径是否存在 if not os.path.isdir(dir_path): print(f"错误:文件夹路径 '{dir_path}' 不存在或不是有效文件夹!") return # 处理后缀参数:统一转为小写,确保 .css 和 CSS 都能匹配 valid_extensions = None if extensions: valid_extensions = [ext.lower() if ext.startswith('.') else f'.{ext.lower()}' for ext in extensions] print(f"筛选后缀:{', '.join(valid_extensions)}") # 打印搜索信息 print(f"开始搜索:\n文件夹:{dir_path}\n搜索内容:{pattern}\n是否正则:{is_regex}") if valid_extensions: print(f"筛选后缀:{', '.join(valid_extensions)}") print('='*60) # 遍历文件夹(包括子文件夹) file_count = 0 # 统计遍历的文件数 match_count = 0 # 统计匹配的文件数 for root, _, files in os.walk(dir_path): for file_name in files: # 过滤文件后缀 if valid_extensions: file_ext = os.path.splitext(file_name)[1].lower() if file_ext not in valid_extensions: continue # 跳过不符合后缀的文件 file_path = os.path.join(root, file_name) file_count += 1 matched_lines = search_in_file(file_path, pattern, is_regex) if matched_lines: match_count += 1 print(f"\n【匹配到文件】:{file_path}") for line in matched_lines: print(f" {line}") # 打印搜索统计 print(f'\n{"="*60}') print(f"搜索完成!") print(f"共遍历文件数:{file_count}") print(f"匹配到文件数:{match_count}") def main(): # 命令行参数解析(新增 --ext 参数指定文件后缀) parser = argparse.ArgumentParser(description='在指定文件夹中搜索文本或正则表达式(支持指定文件后缀)') parser.add_argument('dir_path', help='要搜索的文件夹路径(绝对/相对路径均可)') parser.add_argument('pattern', help='要搜索的文本或正则表达式') parser.add_argument('-r', '--regex', action='store_true', help='是否按正则表达式匹配(默认否)') parser.add_argument('-e', '--ext', nargs='+', help='指定要搜索的文件后缀(多个用空格分隔,如:-e css js html)') args = parser.parse_args() # 执行搜索 search_in_directory(args.dir_path, args.pattern, args.regex, args.ext) if __name__ == '__main__': main()