如何使用ruamel.yaml将字典Dump为YAML时,使\n、\t等特殊字符正常显示而非保留为转义文本?
我来帮你搞定这个问题!你遇到的核心问题出在代码里的json.dumps() + json.loads()这一步操作——这会把原本的换行、空格等特殊字符转换成JSON风格的转义序列,而且后续用ruamel.yaml导出时,这些转义字符会被当成普通文本保留,没法还原成你想要的多行格式。
问题根源拆解
ruamel.yaml的RoundTripLoader本来就可以把YAML文件加载成保留原始格式信息的特殊字典对象(比如CommentedMap),但你用json.dumps()把这个对象转成JSON字符串时,所有原生的换行符\n会被转义成\\n;再用json.loads()转回来,字符串里就真的存了\n这两个字符,而不是换行符本身。所以最后dump到YAML时,自然会把这些转义字符原样输出。
修复方案
1. 移除多余的JSON转换步骤
首先删掉这两行完全没必要的代码:
data = json.loads(json.dumps(data))
这一步不仅破坏了ruamel.yaml保留的格式信息,还直接导致了转义问题。
2. 用ruamel.yaml的ScalarString处理多行文本
如果你希望多行字符串直接以换行形式输出到YAML(而不是带转义的字符串),可以用ruamel.yaml提供的LiteralScalarString类来包装你的多行字符串,它会告诉YAML解析器把这个字符串当成字面块输出,保留所有换行和空格。
修改后的完整代码如下:
import ruamel.yaml as yaml from ruamel.yaml.scalarstring import LiteralScalarString # 替换成你的原始文件路径 original_file = "your_input.yaml" # 替换成你要更新的字典 other_dict = {} with open(original_file) as file: # 用RoundTripLoader加载,保留原始结构信息 data = yaml.load(file, yaml.RoundTripLoader) # 如果是直接赋值多行字符串,用LiteralScalarString包装 data["description"] = LiteralScalarString("select\n table_name.table_column\n from\n table_info info,\n person\n where id = person_thing\n") # 如果是从other_dict更新,记得把里面的多行字符串也包装一下 # 比如: # if "description" in other_dict: # other_dict["description"] = LiteralScalarString(other_dict["description"]) data.update(other_dict) with open("file_new.yaml", "w") as file: yaml.dump(data, file, default_flow_style=False, Dumper=yaml.RoundTripDumper)
最终输出效果
运行这段代码后,生成的YAML文件会是你期望的格式:
name: Ex info: info: info info: info description: | select table_name.table_column from table_info info, person where id = person_thing
这里的|是YAML的字面块标记,它表示后面的内容会保留所有换行和缩进,完全符合你的需求。如果你不想显示|,也可以尝试FoldedScalarString(它会把连续换行转成空格,适合段落文本),但对于你的示例场景,LiteralScalarString是最匹配的选择。
内容的提问来源于stack exchange,提问作者user14289412




