Подтвердить что ты не робот

Разбор JSON без цитируемых ключей

Я понимаю, что в JSON ключи должны быть окружены двойными кавычками. Однако я использую источник данных, который не цитирует их, что приводит к тому, что анализатор Ruby JSON вызывает ошибку. Есть ли способ выполнить "нестрогий" разбор?

Пример:

>> 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"}
>> 

(Я попытался использовать регулярное выражение, чтобы добавить кавычки перед разбором, но не смог полностью его запустить).

4b9b3361

Ответ 1

Если данные довольно хорошо сформированы иначе, это может сделать простое регулярное выражение:

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

Ответ 2

У меня есть эта же проблема с сторонним фидом данных, но моя возвращает более сложный JSON-подобный ответ, который решения gsub не обрабатывают. После некоторых исследований кажется, что эти фиды данных на самом деле являются объектными литералами JavaScript, которые не требуют цитирования ключей.

Чтобы решить проблему, я добавил камень execjs и установил node.js(возможно, будет работать и драгоценный камень therubyracer). После завершения следующего возвращается корректно обработанный хэш-код ruby.

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

Ответ 3

Интересно, что ваш пример действителен ruby ​​1.9 Синтаксис хэша. Если ваши данные действительно такие же простые (без пробелов или других специальных символов в именах ключей), и вы можете обработать их в безопасном контексте, вы можете просто eval его.

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

Это дает вам символы как ключи, поэтому пост-процесс, если вам нужно превратить их в строки:

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

Ответ 4

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

работал лучше, чем

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

Если у него были пробелы или заглавные буквы, он не удался.

Ответ 5

(Отвечая на мой собственный вопрос) Фрагмент, который был опубликован floyd, был похож на то, что я пробовал - он терпел неудачу, потому что некоторые из моих строк содержат двоеточия. Но я упорствовал и нашел решение:

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