YAML将5e-6加载为字符串而不是数字

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

[当我使用YAML从JSON转储中使用e加载数字时,该数字将作为字符串而不是浮点数加载。

我认为这个简单的例子可以解释我的问题。

import json
import yaml

In [1]: import json

In [2]: import yaml

In [3]: All = {'one':1,'low':0.000001}

In [4]: jAll = json.dumps(All)

In [5]: yAll = yaml.safe_load(jAll)

In [6]: yAll
Out[6]: {'low': '1e-06', 'one': 1}

YAML加载1e-06作为字符串而不是数字吗?我该如何解决?

python json dictionary pyyaml
1个回答
22
投票

问题在于,YAML解析程序设置为与浮点数匹配,如下所示:

Resolver.add_implicit_resolver(
    u'tag:yaml.org,2002:float',
    re.compile(u'''^(?:[-+]?(?:[0-9][0-9_]*)\\.[0-9_]*(?:[eE][-+][0-9]+)?
    |\\.[0-9_]+(?:[eE][-+][0-9]+)?
    |[-+]?[0-9][0-9_]*(?::[0-5]?[0-9])+\\.[0-9_]*
    |[-+]?\\.(?:inf|Inf|INF)
    |\\.(?:nan|NaN|NAN))$''', re.X),
    list(u'-+0123456789.'))

YAML spec将科学记号的正则表达式指定为:

-? [1-9] ( \. [0-9]* [1-9] )? ( e [-+] [1-9] [0-9]* )?

后者使点成为可选,而在隐式解析器中的上述re.compile()模式中不存在该点。

浮点数的匹配可以是固定的,因此它将接受带有e / E但不带小数点且指数不带符号(即隐含+的浮点值:]

import yaml
import json
import re

All = {'one':1,'low':0.000001}

jAll = json.dumps(All)

loader = yaml.SafeLoader
loader.add_implicit_resolver(
    u'tag:yaml.org,2002:float',
    re.compile(u'''^(?:
     [-+]?(?:[0-9][0-9_]*)\\.[0-9_]*(?:[eE][-+]?[0-9]+)?
    |[-+]?(?:[0-9][0-9_]*)(?:[eE][-+]?[0-9]+)
    |\\.[0-9_]+(?:[eE][-+][0-9]+)?
    |[-+]?[0-9][0-9_]*(?::[0-5]?[0-9])+\\.[0-9_]*
    |[-+]?\\.(?:inf|Inf|INF)
    |\\.(?:nan|NaN|NAN))$''', re.X),
    list(u'-+0123456789.'))

data = yaml.load(jAll, Loader=loader)
print 'data', data

结果:

data {'low': 1e-06, 'one': 1}

JSON允许使用的数字与YAML 1.2规范中的正则表达式之间存在差异(关于数字中的必需点和e为小写)。IMO非常清楚JSON specification,因为它不需要'e / E'之前的点,也不需要'e / E'之后的符号:

<< img src =“ https://image.soinside.com/eyJ1cmwiOiAiaHR0cHM6Ly9pLnN0YWNrLmltZ3VyLmNvbS9wbzhBOS5naWYifQ==” alt =“在此处输入图像描述”>“ >>

PyYAML实现确实部分根据JSON规范和部分针对正则表达式来匹配浮点数,并且在应该有效的数字上失败。

ruamel.yaml(这是我的PyYAML的增强版),具有这些更新的模式并且可以正常运行:

import ruamel.yaml
import json

All = {'one':1,'low':0.000001}

jAll = json.dumps(All)

data = ruamel.yaml.load(jAll)
print 'data', data

带有输出:

data {'low': 1e-06, 'one': 1}

ruamel.yaml还接受数字'1.0e6',PyYAML也将其视为字符串。

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