Я только что обновился с ruby 1.9.2 до ruby 1.9.3p0 (2011-10-30 ревизия 33570).Мое приложение rails использует postgresql в качестве базы данных.Системный языковой стандарт UTF8, как и кодировка базы данных.Кодировка по умолчанию для приложения rails также UTF8.У меня есть китайские пользователи, которые вводят китайские и английские символы.Строки хранятся в виде строк в кодировке UTF8.
Версия Rails: 3.0.9
После обновления некоторые из существующих китайских строк в базе данных больше не отображаются корректно.Это влияет не на все строки, а только на те, которые являются частью сериализованного хэша.Все остальные строки, которые хранятся в виде простых строк, по-прежнему выглядят правильными.
Пример:
Это сериализованный хэш, который сохраняется как строка UTF8в базе данных:
broken = "--- !map:ActiveSupport::HashWithIndifferentAccess \ncheckbox: \"1\"\nchoice: \"Round Paper Clips \\xEF\\xBC\\x88\\xE5\\x9B\\x9E\\xE5\\xBD\\xA2\\xE9\\x92\\x88\\xEF\\xBC\\x89\\r\\n\"\ninfo: \"10\\xE7\\x9B\\x92\"\n"
Чтобы преобразовать эту строку в хэш рубина, я десериализовал ее с помощью YAML.load
:
broken_hash = YAML.load(broken)
Возвращает хэш с искаженным содержимым:
{"checkbox"=>"1", "choice"=>"Round Paper Clips ï¼\u0088å\u009B\u009Eå½¢é\u0092\u0088ï¼\u0089\r\n", "info"=>"10ç\u009B\u0092"}
Предполагается, что искаженный материал будет китайским в кодировке UTF8.broken_hash['info'].encoding
говорит мне, что ruby думает, что это #<Encoding:UTF-8>
.Я не согласен.
Интересно, что все остальные строки, которые не были сериализованы ранее, выглядят хорошо.В той же записи другое поле содержит китайские иероглифы, которые выглядят правильно - в консоли rails, консоли psql и браузере.Каждая строка - независимо от того, был ли сериализованный хеш или простая строка - сохранена в базе данных, поскольку обновление тоже выглядит хорошо.
Я пытался преобразовать искаженный текст из возможной неправильной кодировки (как GB2312 или ANSI) до UTF-8, несмотря на утверждение ruby о том, что это уже UTF-8 и, конечно, я потерпел неудачу.Это код, который я использовал:
require 'iconv'
Iconv.conv('UTF-8', 'GB2312', broken_hash['info'])
Сбой, потому что ruby не знает, что делать с недопустимыми последовательностями в строке.
Я действительно хочу запустить скрипт для исправлениявсе старые, предположительно сломанные сериализованные хеш-строки и покончим с этим.Есть ли способ преобразовать эти битые строки во что-то похожее на китайский снова?
Я только что поиграл с закодированной строкой UTF-8 в необработанной строке (называемой «разбитой» в приведенном выше примере).Это китайская строка, которая закодирована в сериализованной строке:
chinese = "\\xEF\\xBC\\x88\\xE5\\x9B\\x9E\\xE5\\xBD\\xA2\\xE9\\x92\\x88\\xEF\\xBC\\x89\\r\\n\"
Я заметил, что ее легко преобразовать в настоящую строку в кодировке UTF-8, удалив ее (исключивescape-косые черты).
chinese_ok = "\xEF\xBC\x88\xE5\x9B\x9E\xE5\xBD\xA2\xE9\x92\x88\xEF\xBC\x89\r\n"
Возвращает правильную китайскую строку в кодировке UTF-8: "(回形针)\r\n"
Вещество разваливается только при использовании YAML.load(...)
для преобразования строки в хэш рубина.Возможно, мне следует обработать необработанную строку до того, как она будет передана в YAML.load
.Просто заставляет меня задуматься, почему это так ...
Интересно!Вероятно, это связано с движком YAML «psych», который теперь используется по умолчанию в 1.9.3.Я переключился на двигатель «syck» с YAML::ENGINE.yamler = 'syck'
, и разорванные строки были правильно проанализированы.