我有一个包含以下数据的文件:
classes:
- 9:00
- 10:20
- 12:10
(等等到21:00)
我使用python3和yaml模块来解析它。确切地说,来源是config = yaml.load (open (filename, 'r'))
。但是,当我print
config
时,我会为这部分数据获得以下输出:
'classes': [540, 630, 730, 820, 910, 1000, 1090, 1180],
列表中的值是整数。
之前,当我使用python2(和BaseLoader
用于YAML)时,我将值作为字符串,我就这样使用它们。 BaseLoader
现在不被接受,因为我想从文件中读取unicode字符串,它给我字节字符串。
那么,首先,为什么pyyaml会将我的数据解析为int?
其次,我如何阻止pyyaml这样做?是否可以而不更改数据文件(例如,不添加!!str
)?
答案 0 :(得分:10)
YAML的文档有点难以解析"所以我可以想象你错过了关于冒号的little bit of info:
通常,YAML坚持使用空格将“:”映射值指示符与值分开。这种限制的好处是“:”字符可以在普通标量中使用,只要它后面没有空格。这允许不带引号的URL和时间戳。它也是混淆的潜在来源,因为“a:1”是一个普通的标量而不是一个关键:值对。
你输入的内容是sexagesimal,你的9:00
被认为类似于9分0秒,相当于总共540秒。
不幸的是,这并没有被构造为一些特殊的Sexagesimal实例,可以用于计算,就像它是一个整数但可以以其原始形式打印。因此,如果要在内部将其用作字符串,则必须单引号:
classes:
- '9:00'
- '10:20'
- '12:10'
这是您转储{'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)
给出:
{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']}
答案 1 :(得分:-3)