如何以前导零作为字符串读取/加载yaml参数?

时间:2019-02-22 04:50:18

标签: yaml python-3.7 pyyaml ruamel.yaml

如何使用前导零作为字符串读取/加载YAML参数并在python 3.7中进行操作?从使用yaml-cpp(yaml 1.2)的C ++工具中,我得到一个包含leading_zero: 00005的文本文件。读取/加载这行代码似乎已转换为int,但是为什么呢?您知道如何处理带有前导零的YAML字符串吗?

ruamel.yaml(yaml 1.2)

import sys
from ruamel.yaml import YAML

yaml = YAML()
inp = "leading_zero: 00005\n"
code = yaml.load(inp)
print(code)
print(code['leading_zero'])
yaml.dump(code, sys.stdout)

输出ruamel.yaml

ordereddict([('leading_zero', 5)])
5
leading_zero: 00005

如您所见,00005没有在命令字典中存储为字符串'00005',但是为什么yaml.dump()会显示正确的数字呢?

pyyaml(yaml 1.1)

import yaml
inp = "leading_zero: 00005\n"
code = yaml.load(inp)
print(code)
print(yaml.dump(code, default_flow_style=False))

输出pyyaml

{'leading_zero': 5}
leading_zero: 5

1 个答案:

答案 0 :(得分:2)

首先,没有YAML字符串,没有集合(映射和序列)和标量。 假设这些标量未标记(如您的情况),则可以将它们标为引号(为简单起见,包括文字/折叠样式)或纯引号。

在正常情况下,加载YAML文档时,带引号的标量将作为字符串加载,并且 普通标量根据其“内容”开放为特殊类型的解释。那 解释可能导致它是布尔值,日期,浮点值。如果这些都不匹配,则将纯标量作为字符串加载。

正常加载情况适用Core Schema。该模式是一个 JSON模式的超集,并且在由 仅应将数字加载为integers。 因此,这回答了您有关如何处理“ YAML字符串”的第一个问题

ruamel.yaml,使用默认值(往返) 模式,如果您尝试保存YAML文档的特定格式, 加载,然后转储该文档(这并不总是可能的,但是 尝试)。尽管它以整数形式加载00005,但实际上它是一个 整数类的子类型,其中包括有关格式的信息 整数(即包括前导零的数量)。如果你的 YAML文件受版本控制,这些事情很好 不要因为您更新了文档的其他部分而更改。

这应该回答您的第二个问题,询问ruamel.yaml为什么在输出中显示正确的标量。

PyYAML不会这样做(如果决定使用ruamel.yaml也不会这样做) safe正在加载)。而且您很幸运,您尝试过像00005这样的标量 进行测试,因为00008将作为字符串加载(因为PyYAML 使用2009年以前的YAML 1.1规范,其中前导零 表示八进制,在YAML 1.2中,八进制以0o开始,并且00015加载 在ruamel.yaml中为数字15,在PyYAML中为数字13:

import sys
import ruamel.yaml
import yaml as pyyaml

yaml_str = """\
- 00005    
- 00008    # this is not an octal in YAML 1.1
- 00015
"""

yaml = ruamel.yaml.YAML()
data = yaml.load(yaml_str)
print('ruamel.yaml:', data, type(data[0]))
yaml.dump(data, sys.stdout)
print('-----------')
data = pyyaml.load(yaml_str)
print('pyyaml:     ', data, type(data[0]))
pyyaml.dump(data, sys.stdout, default_flow_style=False)

给出:

ruamel.yaml: [5, 8, 15] <class 'ruamel.yaml.scalarint.ScalarInt'>
- 00005
- 00008    # this is not an octal in YAML 1.1
- 00015
-----------
pyyaml:      [5, '00008', 13] <class 'int'>
- 5
- 00008
- 13

我知道如何处理以“零”开头的““ yaml字符串”吗? 不会,但是我给您几个选项,具体取决于 加载文档的目的(请明确:我是 ruamel.yaml的作者。)

  • 在默认的往返模式下,我加载 它们的行为类似于整数,但保留外部 特定于输入的外观,因为YAML提供了无尽的 表示任何特定数字(例如5)的方式数量。

  • 如果加载 完成yaml = YAML(typ='safe')之后,您将获得 整数,不会以前导零转储。

  • 如果在执行`yaml = YAML(typ ='base')之后加载,您将获得baseloader和每个 标量加载为字符串

作为程序:

from ruamel.yaml import YAML

for t in ['rt', 'safe', 'base']:   # 'rt' is the default
    data = YAML(typ=t).load("00005")
    dt = type(data)
    print(f'{t:5}  {data!r:7}  {dt}')

给予:

rt     5        <class 'ruamel.yaml.scalarint.ScalarInt'>
safe   5        <class 'int'>
base   '00005'  <class 'str'>

因此,如果您不喜欢往返模式的神奇“整数”,请使用基本 架构并自行处理从YAML标量加载的结果字符串。替代 因为那样会从安全或往返模式中卸载整数匹配的正则表达式, 但这更复杂。