Ответ 1
Если данные довольно хорошо сформированы иначе, это может сделать простое регулярное выражение:
irb(main):009:0> '{name:"hello", age:"23"}'.gsub(/([a-z]+):/, '"\1":')
=> "{\"name\":\"hello\", \"age\":\"23\"}"
Я понимаю, что в 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"}
>>
(Я попытался использовать регулярное выражение, чтобы добавить кавычки перед разбором, но не смог полностью его запустить).
Если данные довольно хорошо сформированы иначе, это может сделать простое регулярное выражение:
irb(main):009:0> '{name:"hello", age:"23"}'.gsub(/([a-z]+):/, '"\1":')
=> "{\"name\":\"hello\", \"age\":\"23\"}"
У меня есть эта же проблема с сторонним фидом данных, но моя возвращает более сложный JSON-подобный ответ, который решения gsub не обрабатывают. После некоторых исследований кажется, что эти фиды данных на самом деле являются объектными литералами JavaScript, которые не требуют цитирования ключей.
Чтобы решить проблему, я добавил камень execjs и установил node.js(возможно, будет работать и драгоценный камень therubyracer). После завершения следующего возвращается корректно обработанный хэш-код ruby.
ExecJS.eval('{name:"hello", age:"23"}')
=> {"name"=>"hello", "age"=>"23"}
Интересно, что ваш пример действителен 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"}
gsub(/(\w+)\s*:/, '"\1":')
работал лучше, чем
gsub(/([a-z]+):/, '"\1":')
Если у него были пробелы или заглавные буквы, он не удался.
(Отвечая на мой собственный вопрос) Фрагмент, который был опубликован floyd, был похож на то, что я пробовал - он терпел неудачу, потому что некоторые из моих строк содержат двоеточия. Но я упорствовал и нашел решение:
gsub(/([\{|\,}])\s*([a-zA-Z]+):/, '\1 "\2":')