如何基于预设模板重排YAML键并保留注释?
基于ruamel.yaml的YAML文件标准化处理方案
依赖准备
- 先安装所需库:
pip install ruamel.yaml
模板定义
先明确你的键顺序规则和行距要求,示例如下:
# 顶层键的优先级顺序,按此排列 KEY_ORDER = [ 'name', 'version', 'description', 'dependencies', 'scripts' ] # 行距配置:数字代表空行数 SPACING_RULES = { 'top_level': 1, # 顶层键之间保留1个空行 'sequence_item_end': 1 # 序列最后一项后添加1个空行 }
完整实现代码
from ruamel.yaml import YAML from ruamel.yaml.comments import CommentedMap, CommentedSequence import os # 初始化YAML处理器,保留原引号格式 yaml = YAML() yaml.preserve_quotes = True def sort_commented_map(commented_map: CommentedMap, key_order: list) -> CommentedMap: """按指定顺序重排CommentedMap的键,保留键的注释""" # 先备份所有键的注释信息 key_comment_backup = {} for key in commented_map: if key in commented_map.ca.items: key_comment_backup[key] = commented_map.ca.items[key] # 按模板顺序构建新的CommentedMap sorted_map = CommentedMap() # 先加入模板中定义的键 for key in key_order: if key in commented_map: sorted_map[key] = commented_map[key] # 恢复对应键的注释 if key in key_comment_backup: sorted_map.ca.items[key] = key_comment_backup[key] # 加入模板未定义的剩余键,放在末尾 for key in commented_map: if key not in key_order: sorted_map[key] = commented_map[key] if key in key_comment_backup: sorted_map.ca.items[key] = key_comment_backup[key] return sorted_map def process_commented_sequence(sequence: CommentedSequence, item_key_order: list) -> CommentedSequence: """处理CommentedSequence:内部项按模板排序,最后一项后加空行""" processed_seq = CommentedSequence() for item in sequence: if isinstance(item, CommentedMap): processed_seq.append(sort_commented_map(item, item_key_order)) else: processed_seq.append(item) # 给最后一项添加后置换行,实现末尾空行 if processed_seq: last_idx = len(processed_seq) - 1 processed_seq.ca.items[last_idx] = [None, None, [('\n', None)], None] return processed_seq def clean_empty_comments(commented_map: CommentedMap): """删除仅包含换行/空白的无效注释""" # 收集需要删除的空注释键 empty_comment_keys = [] for key, comment_tuple in commented_map.ca.items.items(): # 检查前置注释是否为空 if comment_tuple[0] is not None: comment_content = comment_tuple[0].value if comment_content.strip() == '': empty_comment_keys.append(key) # 删除空注释 for key in empty_comment_keys: del commented_map.ca.items[key] # 递归处理嵌套的CommentedMap和CommentedSequence for value in commented_map.values(): if isinstance(value, CommentedMap): clean_empty_comments(value) elif isinstance(value, CommentedSequence): for item in value: if isinstance(item, CommentedMap): clean_empty_comments(item) def apply_top_level_spacing(commented_map: CommentedMap, line_count: int): """给顶层键之间添加指定数量的空行""" keys = list(commented_map.keys()) for idx in range(1, len(keys)): current_key = keys[idx] # 设置当前键的前置空行 commented_map.ca.items[current_key] = [ None, ('\n' * line_count, None), None, None ] def process_single_yaml(input_path: str, output_path: str, key_order: list, spacing_rules: dict): """处理单个YAML文件的完整流程""" # 1. 加载YAML文件 with open(input_path, 'r', encoding='utf-8') as f: data = yaml.load(f) if not isinstance(data, CommentedMap): return # 2. 按模板重排键 sorted_data = sort_commented_map(data, key_order) # 处理嵌套的CommentedSequence for key, value in sorted_data.items(): if isinstance(value, CommentedSequence): sorted_data[key] = process_commented_sequence(value, key_order) # 3. 清理空注释 clean_empty_comments(sorted_data) # 4. 应用行距规则 apply_top_level_spacing(sorted_data, spacing_rules['top_level']) # 5. 保存处理后的文件 with open(output_path, 'w', encoding='utf-8') as f: yaml.dump(sorted_data, f) # 批量处理仓库中的YAML文件 if __name__ == '__main__': target_dir = './your-repository-directory' # 替换为你的仓库路径 for root, _, files in os.walk(target_dir): for file in files: if file.endswith(('.yaml', '.yml')): file_path = os.path.join(root, file) # 直接覆盖原文件,若需备份可修改output_path为其他路径 process_single_yaml(file_path, file_path, KEY_ORDER, SPACING_RULES)
关键逻辑说明
- 键排序与注释保留:通过
CommentedMap的.ca.items属性备份并恢复键的注释,确保排序后注释不丢失。 - 空注释清理:遍历注释内容,过滤掉仅含空白字符的无效注释,避免冗余空行。
- 行距控制:通过给键的前置注释添加指定数量的换行符实现键间空行;给序列最后一项添加后置换行实现序列末尾空行。
- 嵌套结构处理:递归遍历嵌套的
CommentedMap和CommentedSequence,确保所有层级都遵循模板规则。
自定义适配
- 修改
KEY_ORDER列表来定义你的键优先级顺序。 - 调整
SPACING_RULES中的数值控制空行数量,0表示无空行,1表示一个空行。 - 若序列内的项需要独立的键顺序,可在调用
process_commented_sequence时传入自定义的键顺序列表。
内容的提问来源于stack exchange,提问作者pinkfloydfan
相关产品推荐
相关产品推荐

