50

我知道在 SO 上有一些关于此的问题,但我找不到我要找的东西。

我正在使用pyyaml读取(.load().yml文件,修改或添加密钥,然后.dump()再次写入()。问题是我想在转储后保留文件格式,但它会改变。

例如,我编辑键en.test.index.few"Bye"而不是"Hello"

Python:

with open(path, 'r', encoding = "utf-8") as yaml_file:
    self.dict = pyyaml.load(yaml_file)

然后,在更改密钥后:

with open(path, 'w', encoding = "utf-8") as yaml_file:
    dump = pyyaml.dump(self.dict, default_flow_style = False, allow_unicode = True, encoding = None)
    yaml_file.write( dump )

yaml:

前:

en:
  test:
    new: "Bye"
    index:
      few: "Hello"
  anothertest: "Something"

后:

en:
  anothertest: Something
  test:
    index:
      few: Hello
    new: Bye

有没有办法保持相同的格式?例如 qoutes 和 order。我为此使用了错误的工具吗?

我知道原始文件可能并不完全正确,但我无法控制它(它是一个 Ruby on Rails i18n 文件)。

非常感谢。

4

3 回答 3

94

下面,ruamel.yaml改为使用。

ruamel.yaml正在积极维护。与 PyYAML 不同,ruamel.yaml支持:

  • YAML <= 1.2。PyYAML 仅支持 YAML <= 1.1。这是至关重要的,因为 YAML 1.2在一些边缘情况下故意破坏了与 YAML 1.1 的向后兼容性。这通常是一件坏事。在这种情况下,这使 YAML 1.2 成为 JSON 的严格超集。由于 YAML 1.1不是JSON 的严格超集,这是一件好事。
  • 往返保存。当调用yaml.dump()转储由先前调用加载的字典时yaml.load()
    • PyYAML 天真地忽略了所有输入格式——包括注释、排序、引用和空格。像这么多数字垃圾一样丢弃到最近的可用比特桶中。
    • ruamel.yaml巧妙地尊重所有输入格式。一切。整个风格的辣酱玉米饼馅。整个文学界。全部。

库迁移

从 PyYAML 切换到ruamel.yaml现有应用程序通常只需将库导入更改为:

from ruamel import yaml

这是可行的,因为ruamel.yaml它是一个符合 PyYAML API 的 PyYAML 分支。

不需要进行其他更改。yaml.load()andyaml.dump()函数应继续按预期运行。

往返保留及其能为您做什么

为了向后兼容 PyYaml,yaml.load()andyaml.dump()函数默认执行往返保存。为此,请显式传递:

  • 的可选Loader=ruamel.yaml.RoundTripLoader关键字参数yaml.load()
  • 的可选Dumper=ruamel.yaml.RoundTripDumper关键字参数yaml.dump()

ruamel.yaml从文档中“借来”的一个例子:

import ruamel.yaml

inp = """\
# example
name:
  # Yet another Great Duke of Hell. He's not so bad, really.
  family: TheMighty
  given: Ashtaroth
"""

code = ruamel.yaml.load(inp, Loader=ruamel.yaml.RoundTripLoader)
code['name']['given'] = 'Astarte'  # Oh no you didn't.

print(ruamel.yaml.dump(code, Dumper=ruamel.yaml.RoundTripDumper), end='')

它完成了。注释、排序、引用和空格现在将原封不动地保留。

于 2016-04-21T05:32:18.317 回答
5

就我而言,我想要"value 是否包含 a{或 a },否则什么都没有。例如:

 en:
   key1: value is 1
   key2: 'value is {1}'

represent_str()为此,请从模块 PyYaml 中的文件表示器.py 中复制函数,并在字符串包含{或 a时使用另一种样式}

def represent_str(self, data):
    tag = None
    style = None
    # Add these two lines:
    if '{' in data or '}' in data:
        style = '"'
    try:
        data = unicode(data, 'ascii')
        tag = u'tag:yaml.org,2002:str'
    except UnicodeDecodeError:
        try:
            data = unicode(data, 'utf-8')
            tag = u'tag:yaml.org,2002:str'
        except UnicodeDecodeError:
            data = data.encode('base64')
            tag = u'tag:yaml.org,2002:binary'
            style = '|'
    return self.represent_scalar(tag, data, style=style)

要在您的代码中使用它:

import yaml

def represent_str(self, data):
  ...

yaml.add_representer(str, represent_str)

在这种情况下,键和值之间没有差异,这对我来说就足够了。如果您想要键和值的不同样式,请使用函数执行相同的操作represent_mapping

于 2016-10-14T13:44:23.940 回答
2

第一的

使用以下代码表示字典数据:

mapping = list(mapping.items())
    try:
        mapping = sorted(mapping)
    except TypeError:
        pass

这就是改变顺序的原因

第二

阅读时会丢失有关如何呈现标量类型(是否带有双引号)的信息(这是图书馆的主要方法)

概括

您可以基于“Dumper”创建自己的类并重载方法“represent_mapping”以更改字典的呈现方式

为了保存有关标量双引号的信息,您还必须基于“加载器”创建自己的类,但我担心它会影响其他类并且会很难做到

于 2014-02-19T12:26:54.660 回答