2015-05-26 10 views
8

Khi tôi tải một số với e hình thành một bãi chứa JSON với YAML, số lượng được nạp như một chuỗi và không phải là một phao.YAML tải 5e-6 như chuỗi và không phải là một số

Tôi nghĩ rằng ví dụ đơn giản này có thể giải thích vấn đề của tôi.

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} 

tải YAML 1e-06 như là một chuỗi và không phải là một số? Làm thế nào tôi có thể sửa chữa nó?

+0

bản sao có thể có của [Tắt ký pháp khoa học trong kết xuất python json.dumps] (http://stackoverflow.com/questions/18936554/disable-scientific-notation-in-python-json-dumps-output) – SiHa

+3

@SiHa That có thể là một cách để tránh vấn đề này, nhưng vấn đề thực sự là YAML được coi là một superset của JSON và '1e-06' khi bạn thoát ra khỏi' cái json.dumps() '** là ** a đúng Số JSON và AFAICT cũng là số YAML chính xác. PyYAML không phân tích cú pháp chính xác. – Anthon

+0

OK, chỉ là một suy nghĩ ... – SiHa

Trả lời

10

Vấn đề nằm trong thực tế rằng YAML Resolver được thiết lập để phù hợp với nổi như sau:

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'-.')) 

trong khi YAML spec xác định regex cho ký hiệu khoa học như:

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

sau làm cho các dấu chấm tùy chọn, nó không phải là re.compile() mô hình trên.

Việc kết hợp phao có thể được cố định vì vậy nó sẽ chấp nhận các giá trị dấu chấm động với một e/E nhưng không có dấu chấm thập phân và với số mũ không dấu (ví dụ + ngụ ý):

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'-.')) 

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

kết quả trong:

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

Có sự khác biệt giữa những gì JSON cho phép về số và regex trong thông số YAML 1.2 (liên quan đến dấu chấm bắt buộc trong số và e là chữ thường). Các JSON specification là IMO rất rõ ràng ở chỗ nó không yêu cầu chấm trước khi 'e/E' cũng không có nghĩa là đòi hỏi một dấu hiệu sau khi 'e/E':

enter image description here

Việc thực hiện PyYAML không phù hợp nổi một phần theo thông số JSON và một phần chống lại regex và không thành công trên các con số phải hợp lệ.

ruamel.yaml (đó là phiên bản nâng cao của tôi về PyYAML), có những mẫu được cập nhật và làm việc một cách chính xác:

import ruamel.yaml 
import json 

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

jAll = json.dumps(All) 

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

với sản lượng:

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

ruamel.yaml cũng chấp nhận số '1.0e6 ', PyYAML nào cũng xem như một chuỗi.

+1

Nếu tôi hiểu đúng, đây là một cách khách quan một lỗi trong PyYAML? Bạn đã gửi yêu cầu kéo sửa chưa? –

+1

@MarkAmery Tôi đã gửi PR cho PyYAML năm ngoái đã phân tích lại hai nhánh mã (Python2 và Python3) mà không có bất kỳ hình thức phản ứng nào. Dự án này hiện đang hy vọng và tôi sẽ không lãng phí thời gian vào PR cho PyYAML cho đến khi nó reawakens. Sau đó tôi chia tay và tiếp tục với các bản sửa lỗi (cũng có một số điểm nổi bật trên PyYAML), bởi vì tôi phải tiến lên phía trước và không thể chờ đợi nữa. Tôi nghĩ rằng đây là một lỗi, vì nó không thực hiện nguyên tắc mà YAML là siêu của JSON và regex chính xác được đưa ra trong đặc tả YAML. Với sự thay đổi này, tất cả PyYAML hiện tại không thể vượt qua được khi tôi thử. – Anthon

+0

@MarkAmery Để rõ ràng, tôi thay vì sửa các lỗi mà tôi đã khắc phục trong PyYAML và sau đó ngắt nguồn cho chức năng bổ sung (không chấp nhận được với PyYAML) và giữ cho mọi thứ được đồng bộ hóa. – Anthon

Các vấn đề liên quan