You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何用Python的ruamel.yaml保留YAML原有格式(引号、布尔值大小写)

解决ruamel.yaml导出时引号丢失、布尔值小写的问题

我用Python的ruamel.yaml库加载YAML文件,仅需添加若干键值对后原样导出,但导出后出现两个问题:原有字符串的引号丢失,布尔值True被转为小写true。

输入YAML文件

---
# *REQUIRED*
person:
  name: 'John Doe'
  age: '30'
  city: 'Sample City'
  apis:
    - 'bigquery'
    - 'bigquerydatatransfer'
    - 'bigquerystorage'
    - 'bigtableadmin'
    - 'cloudbuild'
    - 'cloudkms'
preferences:
  theme: 'dark'
  language: en_US
  test: '77'
  shared_vpc_service: 'shared-vpc-admin'
  #################################################################

  #################################################################
  # *OPTIONAL* - Add Project to VPC Service Controls Security Perimeter
  # Default: True
  # If Set to False - Project will not be added to VPC Service Controls
  enable_vpc_svc_ctrls: True
  #################################################################

导出后异常的YAML文件

---
# *REQUIRED*
person:
  name: John Doe
  age: '30'
  city: Sample City
  apis:
    - bigquery
    - bigquerydatatransfer
    - bigquerystorage
    - bigtableadmin
    - cloudbuild
    - cloudkms
preferences:
  theme: dark
  language: en_US
  test: '77'
  shared_vpc_service: shared-vpc-admin
  #################################################################

  #################################################################
  # *OPTIONAL* - Add Project to VPC Service Controls Security Perimeter
  # Default: True
  # If Set to False - Project will not be added to VPC Service Controls
  enable_vpc_svc_ctrls: true
  #################################################################

我尝试过的无效代码

def add_quotes(value):
    # Add single quotes if the value is a string and not a boolean
    if isinstance(value, str) and not value.lower() == 'true':
        return f"{value}"
    # Convert boolean values to title case and keep them without quotes
    elif isinstance(value, bool):
        if str(value).lower() == 'true':
            return True
        else:
            return False
    else:
        return value


def process_yaml(node):
    if isinstance(node, dict):
        for key, value in node.items():
            node[key] = process_yaml(value)
    elif isinstance(node, list):
        for i, item in enumerate(node):
            node[i] = process_yaml(item)
    else:
        node = add_quotes(node)
    return node

问题核心原因

ruamel.yaml默认加载时会把带引号的字符串转为普通Python字符串,布尔值转为Python原生bool类型,导出时会按YAML默认规则输出(无需引号的字符串自动去掉引号,布尔值统一小写)。要保留原格式,必须利用ruamel.yaml的格式保留特性,而非手动修改字符串。

正确实现代码

from ruamel.yaml import YAML
from ruamel.yaml.scalarstring import SingleQuotedScalarString
from ruamel.yaml.scalarbool import BoolScalar

def load_yaml_with_format(input_path):
    yaml = YAML()
    yaml.preserve_quotes = True  # 开启引号保留功能

    # 自定义布尔值加载逻辑,保留原大小写格式
    def bool_loader(loader, node):
        raw_value = loader.construct_scalar(node)
        return BoolScalar(raw_value == 'True')
    
    yaml.constructor.add_constructor('tag:yaml.org,2002:bool', bool_loader)

    with open(input_path, 'r', encoding='utf-8') as f:
        return yaml.load(f), yaml

def add_custom_keys(data):
    # 示例:添加带单引号的新键值对
    data['person']['email'] = SingleQuotedScalarString('john.doe@example.com')
    return data

def save_yaml_with_format(data, yaml, output_path):
    # 自定义布尔值导出逻辑,输出大写True/False
    def bool_dumper(dumper, value):
        return dumper.represent_scalar('tag:yaml.org,2002:bool', 'True' if value else 'False')
    
    yaml.representer.add_representer(BoolScalar, bool_dumper)

    with open(output_path, 'w', encoding='utf-8') as f:
        yaml.dump(data, f)

# 执行流程
input_file = 'input.yaml'
output_file = 'output.yaml'

yaml_data, yaml_obj = load_yaml_with_format(input_file)
yaml_data = add_custom_keys(yaml_data)
save_yaml_with_format(yaml_data, yaml_obj, output_file)

代码说明

  1. yaml.preserve_quotes = True:让ruamel.yaml自动保留原有字符串的引号格式,无需手动拼接引号。
  2. 自定义布尔值加载器:将YAML中的True/False转为BoolScalar类型(而非原生bool),保留原始大小写信息。
  3. 自定义布尔值导出器:导出时将BoolScalar类型转为大写的True/False字符串,匹配原文件格式。
  4. 新增字符串处理:用SingleQuotedScalarString包裹新增字符串,确保新内容也遵循原文件的引号风格。

内容的提问来源于stack exchange,提问作者evidCoder

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.03 15:45:13