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

问题描述 投票:0回答:1

如何以前导零作为字符串读取/加载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)

output ruamel.yaml

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

正如您所看到的,00005未在ordereddict中存储为字符串'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))

output pyyaml

{'leading_zero': 5}
leading_zero: 5
yaml python-3.7 pyyaml ruamel.yaml
1个回答
2
投票

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

在加载YAML文档的正常情况下,引用的标量将作为字符串加载,并且普通标量打开以作为特殊类型进行解释,具体取决于其“内容”。这种解释可能导致它是一个布尔值,一个日期,一个浮点值。如果这些都不匹配,则将普通标量加载为字符串。

正常的装载情况适用于Core Schema。该模式是JSON模式的超集,并且在由数字组成的两个普通标量中,只应加载为integers。所以这回答了关于如何处理“YAML字符串”的第一个问题

ruamel.yaml,使用默认(往返)模式,尝试在加载时保留YAML文档的特定格式,然后转储该文档(这并不总是可行,但它会尝试)。虽然它将00005作为整数加载,但它实际上是整数类的子类型,其包括有关整数格式的信息(即包括前导零的数量)。如果您的YAML文档处于版本控制之下,那么这些事情不会因为您更新文档的其他部分而发生变化。

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

PyYAML不会这样做(如果决定使用safe加载,ruamel.yaml也不会这样做)。而且你很幸运你为你的测试尝试了像00005这样的标量,因为00008将加载为一个字符串(因为PyYAML使用2009年之前的YAML 1.1规范,其中前导零表示八进制,在YAML 1.2 octals中以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标量加载的结果字符串。另一种方法是从安全或往返模式卸载整数匹配正则表达式,但这更复杂。

© www.soinside.com 2019 - 2024. All rights reserved.