MySQL SUBSTRING () с кодировкой не-utf8 - PullRequest
0 голосов
/ 11 декабря 2018

У меня есть база данных MySQL с кодировкой latin1, и я борюсь с функцией SUBSTRING(), которая, очевидно, считает байты, а не символы, как показано в следующем сценарии:

MySQL [hozana]> set names utf8;
Query OK, 0 rows affected (0.00 sec)

MySQL [hozana]> SELECT SUBSTRING('ééééé', 1, 3);
+-------------------------------+
| SUBSTRING('ééééé', 1, 3)      |
+-------------------------------+
| ééé                           |
+-------------------------------+

Пока все нормально, давайте переключим соединение в кодировку * 1006. *

MySQL [hozana]> set names latin1;
Query OK, 0 rows affected (0.00 sec)

MySQL [hozana]> SELECT SUBSTRING('ééééé', 1, 3);
+-------------------------------+
| SUBSTRING('ééééé', 1, 3)      |
+-------------------------------+
| é�                             |
+-------------------------------+

Единственный способ, который я нашел прямо сейчас, - это преобразовать строку в utf-8 перед функцией SUBSTRING () и преобразовать еевернуться к latin1 потом.Что очень уродливо ...

MySQL [hozana]> select convert(cast(convert(substring(convert(cast(convert('éééé' using  latin1) as binary) using utf8), 1, 3) using utf8) as binary) using latin1);
+--------------------------------------------------------------------------------------------------------------------------------------------------+
| convert(cast(convert(substring(convert(cast(convert('éééé' using  latin1) as binary) using utf8), 1, 3) using utf8) as binary) using latin1)     |
+--------------------------------------------------------------------------------------------------------------------------------------------------+
| ééé                                                                                                                                              |
+--------------------------------------------------------------------------------------------------------------------------------------------------+

Мой вопрос такой: какую конфигурацию нужно сделать, чтобы SUBSTRING() работал в latin1?

Примечание

Вот конфигурация до и после set names:

MySQL [hozana]> SELECT VERSION();
+-----------+
| VERSION() |
+-----------+
| 5.5.54    |
+-----------+

MySQL [hozana]> set names utf8;
Query OK, 0 rows affected (0.00 sec)

MySQL [hozana]> SHOW SESSION VARIABLES LIKE 'character\_set\_%';
+--------------------------+--------+
| Variable_name            | Value  |
+--------------------------+--------+
| character_set_client     | utf8   |
| character_set_connection | utf8   |
| character_set_database   | latin1 |
| character_set_filesystem | binary |
| character_set_results    | utf8   |
| character_set_server     | latin1 |
| character_set_system     | utf8   |
+--------------------------+--------+

MySQL [hozana]> set names latin1;
Query OK, 0 rows affected (0.00 sec)

MySQL [hozana]> SHOW SESSION VARIABLES LIKE 'character\_set\_%';
+--------------------------+--------+
| Variable_name            | Value  |
+--------------------------+--------+
| character_set_client     | latin1 |
| character_set_connection | latin1 |
| character_set_database   | latin1 |
| character_set_filesystem | binary |
| character_set_results    | latin1 |
| character_set_server     | latin1 |
| character_set_system     | utf8   |
+--------------------------+--------+

1 Ответ

0 голосов
/ 14 декабря 2018

Ошибка пользователя.

Когда вы говорите SET NAMES latin1, вы объявляете MySQL, что байты, поступающие от клиента (вас), закодированы в латинице 1.Но они не были.Они все еще были в utf8.

Когда вы набрали ééééé, сгенерированные байты были такими: 10 байтов C3A9C3A9C3A9C3A9C3A9 Они были отправлены в mysql как 10 символы латиницы 1а именно ééééé.SUBSTRING, как и требовалось, вырезал первые 3 символа (но они были латинскими 1 символами: éÃ, hex C3A9C3 и доставлял их обратно вашему клиенту UTF-8, который интерпретировал C3A9 как é, затем заткнул рот недействительным UTF-8, гексом C3 и вырвал свой терминал черным бриллиантом («ХАРАКТЕР ЗАМЕНЫ»).

Поэтому всегда устанавливайте кодирование клиента , либо через что-то в механизме соединения, либо с помощью SET NAMES. Если вы укажете его неправильно, могут возникнуть всевозможные неприятности. Увы, это нерешите вашу проблему напрямую, но она решает множество других вещей, которые могут произойти.

О, другое дело. Вы говорите, что у вас есть «база данных MySQL с кодировкой latin1». Это нормально. Вы все равно должны указатьклиент должен быть закодирован в (очевидно) utf8 или utf8mb4. MySQL преобразует в кодировку столбца , когда вы делаете INSERT, и конвертирует обратно другим способом, когда вы делаете SELECT. Сé существует в latin1, а также utf8, (и то же самое для всех других западноевропейских акцентированных букв), все должно быть хорошо.

Возможно, вы сформулировали Вопрос с буквальным.Ну, это не обязательно отражает SELECTing из таблицы.Итак, я создал таблицу со столбцом latin1 и столбцом utf8, каждый из которых содержал ééééé, и проверил, что значения HEX и LENGTH различны.Затем тестирование SELECT SUBSTRING(col, 1, 3) правильно выдало ééé в обоих случаях.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...