使用ruamel.yaml处理YAML文件时多行字符串空行缩进异常的解决方法
使用ruamel.yaml处理YAML文件时多行字符串空行缩进异常的解决方法
我之前也碰到过类似的问题,用ruamel.yaml处理带空行的块样式字符串时,dump后空行丢失缩进确实挺头疼的。结合我的经验和踩过的坑,给你几个可行的解决方案:
方法一:调整ruamel.yaml的dump配置
首先确保你用的是最新版的ruamel.yaml(旧版本可能存在格式保留的bug),然后通过配置dump参数来强制保留缩进格式。这种方法最简单,适合大多数场景:
from ruamel.yaml import YAML # 初始化YAML对象并配置格式保留参数 yaml = YAML() yaml.preserve_quotes = True # 保留原始引号(如果有的话) yaml.indent(mapping=4, sequence=4, offset=2) # 设置映射、序列的缩进规则 # 加载原始YAML文件 with open('input.yaml', 'r', encoding='utf-8') as f: data = yaml.load(f) # 保存处理后的文件 with open('output.yaml', 'w', encoding='utf-8') as f: yaml.dump(data, f)
这里的indent方法可以根据你的YAML实际缩进层级调整,比如mapping=4表示每个映射层级缩进4个空格,这样块字符串里的空行就能和周围内容保持一致的缩进了。
方法二:手动遍历处理多行字符串的空行
如果调整配置后还是没解决问题,可以手动遍历YAML结构,找到所有多行字符串,将空行替换为带对应缩进的内容。这种方法更灵活,适合复杂结构的YAML:
from ruamel.yaml import YAML from ruamel.yaml.comments import CommentedMap, CommentedSeq def fix_empty_lines(node, current_indent=0): # 计算当前层级下多行字符串的缩进(根据你的实际YAML结构调整,这里假设每层缩进4) content_indent = ' ' * (current_indent + 4) if isinstance(node, CommentedMap): for key, value in node.items(): if isinstance(value, str) and '\n' in value: # 拆分多行字符串,处理空行 lines = value.split('\n') fixed_lines = [] for line in lines: # 识别空行,替换为带缩进的空行 if not line.strip(): fixed_lines.append(content_indent) else: fixed_lines.append(line) node[key] = '\n'.join(fixed_lines) else: # 递归处理子节点 fix_empty_lines(value, current_indent + 4) elif isinstance(node, CommentedSeq): for item in node: fix_empty_lines(item, current_indent + 4) # 加载并处理文件 yaml = YAML() with open('input.yaml', 'r', encoding='utf-8') as f: data = yaml.load(f) fix_empty_lines(data) with open('output.yaml', 'w', encoding='utf-8') as f: yaml.dump(data, f)
注意要根据你的YAML实际缩进层级调整content_indent的计算逻辑,确保空行的缩进和其他代码行一致。
方法三:用LiteralScalarString明确指定块样式字符串
ruamel.yaml提供了LiteralScalarString类,可以明确标记字符串为块样式,确保完全保留原始的换行、缩进和空行。如果是手动修改字符串内容,这种方法也很有用:
from ruamel.yaml import YAML from ruamel.yaml.scalarstring import LiteralScalarString yaml = YAML() yaml.preserve_quotes = True # 保留原始格式 # 加载文件 with open('input.yaml', 'r', encoding='utf-8') as f: data = yaml.load(f) # 如果是手动修改字符串,用LiteralScalarString包裹内容(可选,加载后的原始字符串已经是该类型) # data["'Page' As screen"]["gal As gallery"]["Items"] = LiteralScalarString("""={ # someItem: someValue, # # someItem2: someValue2 # }""") # 保存文件 with open('output.yaml', 'w', encoding='utf-8') as f: yaml.dump(data, f)
这种方法能确保块样式字符串的所有格式细节都被完整保留,包括连续空行的缩进。
备注:内容来源于stack exchange,提问作者niach




