PyYaml将'9:00'解析为int

glu*_*k47 4 yaml pyyaml python-3.x

我有一个包含以下数据的文件:

classes:
  - 9:00
  - 10:20
  - 12:10
Run Code Online (Sandbox Code Playgroud)

(等到21:00)

我使用python3和yaml模块来解析它.确切地说,来源是config = yaml.load (open (filename, 'r')).但是,当我print config,我得到这部分数据的以下输出:

'classes': [540, 630, 730, 820, 910, 1000, 1090, 1180],
Run Code Online (Sandbox Code Playgroud)

列表中的值是整数.

以前,当我使用python2(和BaseLoaderYAML)时,我将值作为字符串,我就这样使用它们.BaseLoader现在不能接受,因为我想从文件中读取unicode字符串,它给我字节字符串.

那么,首先,为什么pyyaml会将我的数据解析为整数?

其次,我如何防止pyyaml这样做?是否可以在不更改数据文件的情况下执行此操作(例如,不添加!!str)?

Ant*_*hon 10

YAML的文档有点难以"解析",所以我可以想象你错过关于冒号的一点点信息:

通常,YAML坚持将":"映射值指示符与空格分隔.这种限制的好处是":"字符可以在普通标量中使用,只要它后面没有空格.这允许不带引号的URL和时间戳.它也是混淆的潜在来源,因为"a:1"是一个普通的标量而不是一个关键:值对.

而你在输入中所拥有的是一个六分相,你的9:00被认为类似于9分0秒,相当于总共540秒.

不幸的是,这并没有被构造为一些特殊的Sexagesimal实例,可以用于计算,就像它是一个整数但可以以其原始形式打印.因此,如果要在内部将其用作字符串,则必须单引号:

classes:
  - '9:00'
  - '10:20'
  - '12:10'
Run Code Online (Sandbox Code Playgroud)

这是你转储时会得到的{'classes': ['9:00', '10:20', '12:10']}(并注意到明确classes无法获得任何引号).

BaseLoader给你字符串是不足为奇的.该BaseConstructor所使用的BaseLoader手柄任何标为字符串,包括整数,布尔和"你" sexagesimals:

import ruamel.yaml as yaml

yaml_str = """\
classes:
  - 12345
  - 10:20
  - abc
  - True
"""

data = yaml.load(yaml_str, Loader=yaml.BaseLoader)
print(data)
data = yaml.load(yaml_str, Loader=yaml.SafeLoader)
Run Code Online (Sandbox Code Playgroud)

得到:

{u'classes': [u'12345', u'10:20', u'abc', u'True']}
{'classes': [12345, 620, 'abc', True]}
Run Code Online (Sandbox Code Playgroud)

如果你真的不想使用引号,那么你必须"重置"以数字开头的标量的隐式解析器:

import ruamel.yaml as yaml
from ruamel.yaml.resolver import Resolver
import re

yaml_str = """\
classes:
  - 9:00
  - 10:20
  - 12:10
"""

for ch in list(u'-+0123456789'):
    del Resolver.yaml_implicit_resolvers[ch]
Resolver.add_implicit_resolver(
    u'tag:yaml.org,2002:int',
    re.compile(u'''^(?:[-+]?0b[0-1_]+
    |[-+]?0o?[0-7_]+
    |[-+]?(?:0|[1-9][0-9_]*)
    |[-+]?0x[0-9a-fA-F_]+)$''', re.X),  # <- copy from resolver.py without sexagesimal support
    list(u'-+0123456789'))

data = yaml.load(yaml_str, Loader=yaml.SafeLoader)
print(data)
Run Code Online (Sandbox Code Playgroud)

给你:

{'classes': ['9:00', '10:20', '12:10']}
Run Code Online (Sandbox Code Playgroud)