2010-01-13 28 views
22

Tôi hiểu rằng trong JSON, các khóa được cho là được bao quanh trong dấu ngoặc kép. Tuy nhiên, tôi đang sử dụng một nguồn dữ liệu không trích dẫn chúng, điều này làm cho trình phân tích cú pháp JSON của Ruby đưa ra một lỗi. Có cách nào để thực hiện phân tích cú pháp 'không nghiêm ngặt' không?Phân tích cú pháp JSON mà không có khóa được trích dẫn

Ví dụ:

>> JSON.parse('{name:"hello", age:"23"}') 
JSON::ParserError: 618: unexpected token at '{name:"hello", age:"23"}' 
    from /Library/Ruby/Gems/1.8/gems/json-1.1.7/lib/json/common.rb:122:in `parse' 
    from /Library/Ruby/Gems/1.8/gems/json-1.1.7/lib/json/common.rb:122:in `parse' 
    from (irb):5 
>> JSON.parse('{"name":"hello", "age":"23"}') 
=> {"name"=>"hello", "age"=>"23"} 
>> 

(tôi đã cố gắng sử dụng một biểu thức chính quy để thêm dấu ngoặc kép trong trước khi phân tích cú pháp, nhưng không thể làm cho nó hoàn toàn làm việc).

+9

Nếu nó không phải là JSON, nó không phải là JSON. Nó có thể giống với nó một cách hời hợt, nhưng giải pháp chính xác là sửa chữa mã nguồn để nó thực sự mang lại cho JSON không phải là một cái gì đó trông giống như một JSON-nhưng-không-như-là-không-. –

+0

Rất tiếc, tôi không có quyền kiểm soát nguồn, đó là từ bên thứ ba. Ví dụ: –

+0

http://www.google.com/ig/calculator?hl=vi&q=100AUD=?USD chẳng hạn yêu cầu những gì anh ta yêu cầu. @ floyd có giải pháp dưới đây - và có thể chấp nhận được – Rabbott

Trả lời

15

Nếu dữ liệu là khá tốt hình thành khác hơn thế, một regex đơn giản có thể làm nó:

irb(main):009:0> '{name:"hello", age:"23"}'.gsub(/([a-z]+):/, '"\1":') 
=> "{\"name\":\"hello\", \"age\":\"23\"}" 
+5

''{name:" hello ", age:" 23 "} '.gsub (/ ([\ w] +): /,' "\ 1": ') 'làm cho nó mạnh hơn một chút! – ankimal

+3

Không đúng cách nếu giá trị là dấu thời gian. Ví dụ: {name: "Hello", time: "12:59:59"} – Prabhakar

6

Thật thú vị, ví dụ của bạn là cú pháp băm 1.9 hợp lệ ruby ​​hợp lệ. Nếu dữ liệu của bạn thực sự đơn giản như thế này (không có dấu cách hoặc các ký tự đặc biệt khác trong tên khóa), và bạn có thể xử lý nó trong một ngữ cảnh an toàn, bạn chỉ có thể eval nó.

irb(main):001:0> eval '{name:"hello", age:"23"}' 
=> {:name=>"hello", :age=>"23"} 

này mang đến cho bạn những biểu tượng như là chìa khóa, vì vậy sau quá trình nếu bạn cần để biến chúng thành chuỗi:

irb(main):002:0> eval('{name:"hello", age:"23"}').reduce({}) {|h,(k,v)| h[k.to_s] = v; h} 
=> {"name"=>"hello", "age"=>"23"} 
+1

Cảm ơn vì điều đó, mặc dù kể từ khi tôi đang sử dụng 1.8.7 đó không phải là một lựa chọn tại thời điểm này. –

+0

Giải pháp rất sạch sẽ! Cảm ơn. Sạch hơn nhiều để tận dụng thông tin này từ Google thay vì săn lùng một viên ngọc khác. – ylluminate

+5

Điều này có thể rất nguy hiểm ... (ví dụ: nếu bạn nhận được từ máy chủ '{a: 1}; \' rm -rf/\ '') – ghayes

1

(Trả lời câu hỏi của riêng tôi) đoạn rằng Floyd posted cũng tương tự như những gì tôi đã cố gắng - nó đã thất bại vì một số chuỗi của tôi chứa dấu hai chấm. Nhưng tôi vẫn kiên trì và tìm thấy một giải pháp:

gsub(/([\{|\,}])\s*([a-zA-Z]+):/, '\1 "\2":') 
+0

Vấn đề là regex của bạn cũng sẽ thay thế các trường hợp "key =" bên trong giá trị được trích dẫn mà giá trị không muốn. –

2
gsub(/(\w+)\s*:/, '"\1":') 

làm việc tốt hơn so với

gsub(/([a-z]+):/, '"\1":') 

Nếu nó đã có khoảng trắng hoặc chữ in hoa, nó thất bại.

8

Tôi có cùng vấn đề này với nguồn cấp dữ liệu của bên thứ ba, nhưng tôi trả về phản hồi giống JSON phức tạp hơn mà các giải pháp gsub không xử lý. Sau khi một số nghiên cứu xuất hiện các nguồn cấp dữ liệu này thực sự là các đối tượng JavaScript mà không yêu cầu các khóa được trích dẫn.

Để giải quyết vấn đề tôi đã thêm đá quý execjs và node.js đã cài đặt (đá quý therubyracer có thể hoạt động tốt). Sau khi hoàn thành, sau đây trả về một băm băm được phân tích cú pháp chính xác.

ExecJS.eval('{name:"hello", age:"23"}') 
=> {"name"=>"hello", "age"=>"23"} 
0

Đây là cách tôi đã phải giải quyết nó:

JSON.parse(broken_json_string.gsub(/'([^']+)':/, '"\1":')) 

Một số những điều trên giả định các phím chỉ chứa các chữ cái; Dễ dàng hơn để chỉ nói "bất kỳ ký tự nào không phải là một dấu nháy đơn" (trong trường hợp của chúng ta, tất cả các phím được bao bọc trong dấu nháy đơn).

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