Почему ruby не обнаруживает недопустимую кодировку, в то время как mysql это делает?

#mysql #ruby #utf-8 #internationalization #utf8mb4

#mysql #ruby #utf-8 #интернационализация #utf8mb4

Вопрос:

Я загружаю некоторые RSS-каналы с YouTube, которые имеют недопустимый UTF8. Я могу создать аналогичную строку ruby, используя

 bad_utf8 = "u{61B36}"
bad_utf8.encoding # => #<Encoding:UTF-8>
bad_utf8.valid_encoding? # => true
  

Ruby считает, что это допустимая кодировка UTF-8, и я почти уверен, что это не так.

При общении с Mysql я получаю ошибку, подобную такой

 require 'mysql2'
client = Mysql2::Client.new(:host => "localhost", :username => "root")
client.query("use test");

bad_utf8 = "u{61B36}"
client.query("INSERT INTO utf8 VALUES ('#{moo}')")

# Incorrect string value: 'xF1xA1xACxB6' for column 'string' at row 1 (Mysql2::Error)
  

Как я могу обнаружить или исправить эти недопустимые типы кодировок, прежде чем отправлять их в MySQL?

Комментарии:

1. Итак, я думаю, проблема может заключаться в том, что MySQL поддерживает только базовую многоязычную плоскость, где as ruby поддерживает все.

2. Ruby поддерживает все? С каких пор?

Ответ №1:

Я не полагаюсь на встроенную в Ruby строку.valid_encoding?, потому что также возможно следующее:

 irb
1.9.3-p125 :001 > bad_utf8 = "u{0}"
 => "u0000" 
1.9.3-p125 :002 > bad_utf8.valid_encoding?
 => true 
1.9.3-p125 :003 > bad_utf8.encoding
 => #<Encoding:UTF-8>
  

Это допустимый UTF-8 (Ссылка:https://en.wikipedia.org/wiki/Utf8), но я обнаружил, что наличие символа NULL в строке часто является намеком на предыдущую ошибку преобразования (например, при перекодировании с недопустимой информации о кодировке, найденной на html-страницах).

Я создал свою собственную функцию проверки для «Модифицированного UTF-8», которая может использовать опцию:bmp_only для ограничения проверки базовой многоязычной плоскостью (0x1-0xffff). Этого должно быть достаточно для большинства современных языков (Ссылка:https://en.wikipedia.org/wiki/Unicode_plane ).

Найдите средство проверки здесь: https://gist.github.com/2295531

Комментарии:

1. u0000 допустимо. Это исключение находится в контексте «Измененного UTF-8», используемого Java DataInput / DataOutput docs.oracle.com/javase/6/docs/api/java/io/DataInput.html

2. Это правильно. В приведенной выше сути используется модифицированный UTF-8, я сделаю примечание там, чтобы сделать его более понятным.

Ответ №2:

возможно, потому, что кодовая точка не лежит в базовой многоязычной плоскости , которая является единственными символами, которые MySQL допускает в своем наборе символов «utf8».

Более новые версии mysql имеют другой набор символов под названием «utf8mb4», который поддерживает символы Unicode за пределами BMP.

Но вы, вероятно, не хотите это использовать. Внимательно рассмотрите свои варианты использования. Несколько реальных человеческих языков (если таковые имеются) используют символы вне BMP.