Как заменить устаревший iconv на String # encode для некорректной коррекции UTF8 - PullRequest
4 голосов
/ 03 февраля 2012

Я получаю источники из Интернета, и иногда кодировка материала не соответствует 100% -ной последовательности байтов UTF8.Я использую iconv, чтобы беззвучно игнорировать эти последовательности для получения очищенной строки.

@iconv = Iconv.new('UTF-8//IGNORE', 'UTF-8')
valid_string = @iconv.iconv(untrusted_string)

Однако теперь iconv устарел, я вижу, что его предупреждение об устаревании много.

iconv будетне рекомендуется в будущем, используйте String # encode

Я попытался преобразовать его, используя опции String#encode s :invalid и :replace, но, похоже, он не работает (т.е.неправильная последовательность байтов не была удалена).Как правильно использовать String # encode для этого?

Ответы [ 2 ]

7 голосов
/ 03 февраля 2012

Ответ на этот вопрос:

Есть ли способ в ruby ​​1.9 удалить недопустимые последовательности байтов из строк?

Используйте либо

untrusted_string.chars.select{|i| i.valid_encoding?}.join

или

untrusted_string.encode('UTF-8', :invalid => :replace, :replace => '').encode('UTF-8')
6 голосов
/ 25 сентября 2012

Вопрос, с которым связался Мартейн, имеет два наилучших способа сделать это, но Мартейн внес понятное, но неверное изменение, копируя второй подход к своему ответу здесь.Выполнение .encode ('UTF-8', ). Encode ('UTF-8') не работает.Как указано в исходном ответе на другой вопрос, ключ заключается в кодировании в другую кодировку , а затем обратно в UTF-8.Если ваша исходная строка уже помечена как UTF-8 во внутренних элементах ruby, тогда ruby ​​будет игнорировать любой вызов для кодирования ее как UTF-8.

В следующих примерах я буду использовать "a # {0xFF.chr} b ".force_encoding ('UTF-8'), чтобы создать строку, которую ruby ​​считает UTF-8, но которая содержит недопустимые байты UTF-8.

1.9.3p194 :019 > "a#{0xFF.chr}b".force_encoding('UTF-8')
 => "a\xFFb" 
1.9.3p194 :020 > "#{0xFF.chr}".force_encoding('UTF-8').encoding
 => #<Encoding:UTF-8> 

Обратите внимание, что кодирование в UTF-8 ничего не делает:

1.9.3p194 :016 > "a#{0xFF.chr}b".force_encoding('UTF-8').encode('UTF-8', :invalid => :replace, :replace => '').encode('UTF-8')
 => "a\xFFb" 

Но кодирование во что-то другое (UTF-16) и затем обратно в UTF-8 очищает строку:

1.9.3p194 :017 > "a#{0xFF.chr}b".force_encoding('UTF-8').encode('UTF-16', :invalid => :replace, :replace => '').encode('UTF-8')
 => "ab" 
...