Python脚本修改YAML文件时多行字段格式异常的解决方案咨询
Python脚本修改YAML文件时多行字段格式异常的解决方案咨询
我完全理解你遇到的困扰——用PyYAML修改YAML文件后,原本整洁的多行块字符串(用|定义的那种)变成了带转义字符或者被引号包裹的格式,严重影响了文档的可读性。其实这个问题的核心在于PyYAML默认的序列化逻辑不会保留原YAML中的块标元数据,咱们可以通过两种方式解决:
方案一:改用ruamel.yaml库(推荐)
PyYAML更适合简单的YAML解析/序列化,而ruamel.yaml是专门为保留YAML原有格式(包括块标量、注释、键顺序)设计的工具,处理这种场景非常顺手。
步骤1:安装依赖
pip install ruamel.yaml
步骤2:修改你的脚本
把原来的PyYAML相关代码替换成ruamel.yaml的实现,调整后的核心代码如下:
import json import sys import logging from datetime import datetime from ruamel.yaml import YAML # Configure logging logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(levelname)s - %(message)s') def update_yaml_files(files, field, author_name, author_email): logging.info("Starting update_yaml_files function") files_path = json.loads(files) logging.info(f"Parsed JSON input: {files_path}") # 初始化ruamel.yaml对象,开启保留引号和原格式的设置 yaml = YAML() yaml.preserve_quotes = True yaml.width = 4096 # 避免自动换行截断 for file in files_path: logging.info(f"Processing file: {file}") try: with open(file, 'r', encoding='utf-8') as f: data = yaml.load(f) logging.info(f"Loaded YAML data from {file}: {data}") data['approvals'][field]['name'] = author_name data['approvals'][field]['email'] = author_email logging.info(f"Updated name and email for field '{field}'") if 'approvaldate' in data['approvals'][field]: data['approvals'][field]['approvaldate'] = datetime.now().strftime("%d-%b-%Y") logging.info(f"Updated approval date for field '{field}'") print(f"Updated data with approval date for {file}: {data}") with open(file, 'w', encoding='utf-8') as f: yaml.dump(data, f) logging.info(f"Successfully wrote updated data to {file}") except Exception as e: logging.error(f"Error processing file {file}: {e}") if __name__ == "__main__": if len(sys.argv) != 5: logging.error("Invalid number of arguments. Expected 4 arguments.") sys.exit(1) files = sys.argv[1] field = sys.argv[2] author_name = sys.argv[3] author_email = sys.argv[4] logging.info("Script started with arguments: "f"files={files}, field={field}, author_name={author_name}, author_email={author_email}") update_yaml_files(files, field, author_name, author_email) logging.info("Script finished")
这样修改后,ruamel.yaml会自动识别原文件中的块标量格式(|),并在写入时完整保留,不会出现转义字符或者引号包裹的问题。
方案二:自定义PyYAML的字符串序列化器(不推荐,仅作备选)
如果不想更换库,可以通过自定义PyYAML的代表器(Representer)来强制多行字符串使用块标量格式输出,但这种方式会影响所有字符串的序列化,灵活性不如ruamel.yaml:
修改代码片段
在原脚本的yaml导入后添加以下自定义代表器:
import yaml def multi_line_str_presenter(dumper, data): # 仅对包含换行符的字符串使用块标量格式 if '\n' in data: return dumper.represent_scalar('tag:yaml.org,2002:str', data, style='|') # 单行字符串保持原有格式 return dumper.represent_scalar('tag:yaml.org,2002:str', data) # 注册自定义代表器 yaml.add_representer(str, multi_line_str_presenter)
然后把原来的yaml.safe_dump替换为yaml.dump(因为safe_dump会忽略自定义代表器),并保留其他参数:
yaml.dump(data, f, default_flow_style=False, sort_keys=False, allow_unicode=True, indent=2, width=4096)
不过这种方式有个小缺点:所有带换行的字符串都会被强制用|输出,哪怕原文件中是其他格式,所以还是推荐第一种方案更稳妥。
备注:内容来源于stack exchange,提问作者delucaezequiel
相关产品推荐
相关产品推荐

