2015-04-24 1 views
2

У меня возникает проблема, когда JSON, созданный скриптом Ruby, несовместим при анализе JavaScripts JSON.parse. Рассмотрим следующий пример:JSON, выпущенный Ruby, не совместим с парсером JSON JavaScript

# Ruby 
require 'json' 
hash = {} 
hash["key"] = "value with \u001a unicode" 
hash.to_json 
=> '{"key":"value with \u001a unicode"}' 

// JavaScript 
JSON.parse('{"key":"value with \u001a unicode"}') 
=> JSON.parse: bad control character in string literal at line 1 column 2 of the JSON data 

Вопрос является юникода характер \u001a. Решением этого является выход \u001a в \\u001a, но дело в том, что \u001a автоматически вставляется в строку Ruby. Я не могу надежно выполнить обработку результата. Любые идеи о том, как это решить?

Обратите внимание, что я хочу позвонить JSON.parse внутри среды выполнения JavaScript, а не внутри интерпретатора Ruby.

+0

Я запустил ваш код, и на самом деле получаю это как вывод: '=>" {\ "key \": \ "value with \\ u001a unicode \"} "' –

+0

Я тоже запустил ваш код, и он работал хорошо. –

+1

Вы смотрите на выход в терминале. '\\ u001a' - это терминал, это физическая строка' \ u001a'. Ruby отображает обратную косую черту как \\, поэтому вы можете указать разницу между единственным символом '\ u001a' и шестью символьными строками, также написанными' \ u001a'. – Max

ответ

2

Короткая версия, что вы интерпретировать вашу строку как выражение Javascript, прежде чем пытаться расшифровать его, как JSON.

U + 001A - это управляющий символ. RFC 4627 explicitly disallows control characters U+0000-U+001F in quoted strings. Ваша проблема здесь заключается не в том, что JSON недействителен, а в том, что вы отменяете свои контрольные символы перед тем, как попытаться проанализировать их как JSON.

Когда вы выгружаете строку "\u001a" из Ruby и копируете и вставляете ее в Javascript-интерпретатор, escape-последовательность преобразуется в неэкранированный символ управления, который не является допустимым символом в JSON! Не запрещенные символы работают очень хорошо - вы можете с радостью принять JSON.parse('["\u0020"]').

Однако, если вы не используете, интерпретируйте строку как Javascript и вместо этого прочитайте ее как необработанные байты, она будет правильно анализировать.

$ irb 
irb(main):001:0> require 'json' 
=> true 
irb(main):003:0> open("out.json", "w") {|f| f.print JSON.dump(["\u001a"]) } 
=> nil 

$ node -e 'require("fs").readFile("out.json", function(err, data) { console.log(JSON.parse(data)); });' 
[ '\u001a' ] 

Если вы собираетесь быть копировать-наклеивать, вы должны быть копирование спасся версию строки, так что, когда строка обрабатывается вашим двигателем Javascript, управляющие последовательности с двойным экранированием должным образом unescape для избежания последовательностей, а не символов. Поэтому, вместо копирования вывода JSON.dump(["\u001a"]), вы должны копировать вывод puts JSON.dump(["\u001a"]).inspect, который будет корректно избегать любых управляющих последовательностей в строке.

+0

Есть ли способ выписать правильно экранированную версию строки? Я пишу строку в файл, а затем кто-то еще читает файл и копирует строку в файл JavaScript (программно). – Max

+0

Если вы пишете его с помощью Javascript, 'JSON.stringify (json_string)'. Если вы пишете его с Ruby, 'JSON.dump (json_string)'. –

0

Мне следующий код ruby ​​дает "{\"key\":\"value with \\u001a unicode\"}" в выводе.

И JSON.parse также abel, чтобы передать его. и дает Object {key: "value with unicode"}.

+0

Вы смотрите на код в терминале. Он экранирует строку String, чтобы вы могли видеть символы. В противном случае, как вы могли бы рассказать разницу между '\ u001a' и' \ u001a'. Поэтому '\\ u001a' - это буквальная строка' \ u001a' без экранирования unicode. Чтобы увидеть разницу, сравните результаты '' \\ u001a ".size' и' '\ u001a" .size'. Обратите внимание, что длина '\\ u001a' равна 6 * не * 7, а это означает, что Ruby отображает' \ escaped. – Max

+0

woow вы правы. виноват. –

0

Согласно RFC:

JSON текст кодируется в кодировке Юникод. Unicode по умолчанию - utf-8.

Я побежал код в IRB и получил следующее:

1.9.3-p484 :001 > require 'json' 
=> true 
1.9.3-p484 :002 > 
1.9.3-p484 :003 > hash = {} 
=> {} 
1.9.3-p484 :004 > hash["key"] = "value with \u001a unicode" 
=> "value with \u001A unicode" 
1.9.3-p484 :005 > hash.to_json 
=> "{\"key\":\"value with \\u001a unicode\"}" 

Затем запустить возвращенную строку в консоли JavaScript, я получаю следующее:

> JSON.parse("{\"key\":\"value with \\u001a unicode\"}") 
> Object {key: "value with unicode"} 

Это возвращая объект. Чтобы получить значение с помощью Юникода, вы должны получить доступ к хэш по телефону:

> str = JSON.parse("{\"key\":\"value with \\u001a unicode\"}") 
> Object {key: "value with unicode"} 
> str.key 
> "value with unicode" 
+0

JSON.parse должен выполняться в среде выполнения JavaScript, а не внутри интерпретатора Ruby. – Max

+0

@Max фактически, тот работает тоже. Просто [скопировали его в консоль Chrome] (http://i.imgur.com/EDIDkUF.png). Это даже разные языки! .. Неважно. –

+0

@ D-side взгляните на принятый ответ, если вы хотите объяснить, почему работает консольный вывод Ruby. Вывод консоли не является точной строкой, возвращаемой вызовом 'to_json'. – Max

Смежные вопросы