4

I have a file with the following data:

classes:
  - 9:00
  - 10:20
  - 12:10

(and so on up to 21:00)

I use python3 and yaml module to parse it. Precisely, the source is config = yaml.load (open (filename, 'r')). But then, when I print config, I get the following output for this part of data:

'classes': [540, 630, 730, 820, 910, 1000, 1090, 1180],

The values in the list are ints.

While previously, when I used python2 (and BaseLoader for YAML), I got the values as strings, and I use them as such. BaseLoader is now not acceptable since I want to read unicode strings from file, and it gives me byte-strings.

So, first, why pyyaml does parse my data as ints?

And, second, how do I prevent pyyaml from doing this? Is it possible to do that without changing data file (e.g. without adding !!str)?

4

2 回答 2

11

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

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

你输入的内容是一个六十进制,你9:00被认为类似于 9 分 0 秒,总共等于 540 秒。

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

classes:
  - '9:00'
  - '10:20'
  - '12:10'

如果你转储,这就是你会得到{'classes': ['9:00', '10:20', '12:10']}的(并注意明确classes没有任何引号)。

BaseLoader你字符串并不奇怪。处理任何标量作为字符串BaseConstructor使用的,包括整数、布尔值和“你的”六十进制数:BaseLoader

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)

给出:

{u'classes': [u'12345', u'10:20', u'abc', u'True']}
{'classes': [12345, 620, 'abc', True]}

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

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)

给你:

{'classes': ['9:00', '10:20', '12:10']}
于 2015-06-23T15:43:56.397 回答
-5

您可能应该检查YAML 的文档

冒号用于映射值。

我想你想要一个字符串而不是整数,所以你应该双引号你的字符串。

于 2014-05-22T19:10:52.283 回答