Проблеми з символами UTF-8; те, що я бачу, це не те, що я зберігав


78

Я спробував використати UTF-8 і зіткнувся з неприємностями.

Я спробував стільки речей; ось результати, які я отримав:

  • ????замість азіатських символів. Навіть за європейський текст, я взяв Se?orза Señor.
  • Дивні халепи (Моджібаке?), Такі як Señorабо 新浪新闻для 新浪新闻.
  • Чорні діаманти, такі як Сеор.
  • Нарешті, я потрапив у ситуацію, коли дані були втрачені або, принаймні, усічені: Sefor Señor.
  • Навіть коли я отримав текст погляд вправо, він не сортувати правильно.

Що я роблю не так? Як я можу виправити код ? Чи можу я відновити дані , якщо так, то як?

Відповіді:


135

Ця проблема мучить учасників цього сайту та багатьох інших.

Ви перерахували п’ять основних випадків CHARACTER SETнеприємностей.

Найкраща практика

Забігаючи вперед, найкраще використовувати CHARACTER SET utf8mb4і COLLATION utf8mb4_unicode_520_ci. (У конвеєрі є нова версія версії Unicode).

utf8mb4є надмножиною того, utf8що він обробляє 4-байтові коди utf8, які потрібні Emoji та деяким китайцям.

За межами MySQL, "UTF-8" відноситься до всіх кодувань розмірів, отже, фактично збігається з кодуванням MySQL utf8mb4, а не utf8.

Я спробую використовувати ці орфографії та великі літери, щоб розрізнити всередині та поза MySQL у наступному.

Огляд того, що ви повинні робити

  • Нехай ваш редактор тощо буде встановлений на UTF-8.
  • Форми HTML повинні починатися як <form accept-charset="UTF-8">.
  • Нехай ваші байти закодуються як UTF-8.
  • Встановіть UTF-8 як кодування, яке використовується в клієнті.
  • Є стовпець / таблиця оголошена CHARACTER SET utf8mb4(перевірте SHOW CREATE TABLE) .
  • <meta charset=UTF-8> на початку HTML
  • Збережені підпрограми отримують поточну кодировку / порівняння. Можливо, їм знадобиться відбудова.

UTF-8 до кінця

Докладніше про комп’ютерні мови (та наступні розділи)

Перевірте дані

Перегляд даних за допомогою інструменту або за SELECTдопомогою не можна довіряти. Занадто багато таких клієнтів, особливо браузерів, намагаються компенсувати неправильне кодування та показують правильний текст, навіть якщо база даних перекручена. Отже, виберіть таблицю та стовпець, що містить текст, який не є англійською мовою, і виконайте

SELECT col, HEX(col) FROM tbl WHERE ...

Буде HEX для правильно збереженого UTF-8

  • Для пробілу (будь-якою мовою): 20
  • Для англійської мови: 4x, 5x, 6x, або7x
  • Для більшості країн Західної Європи букви з наголосом мають бути Cxyy
  • Кирилиця, іврит та фарсі / арабська: Dxyy
  • Більша частина Азії: Exyyzz
  • Emoji та деякі китайські: F0yyzzww
  • Детальніше

Конкретні причини та способи усунення побачених проблем

Зрізаний текст ( Seдля Señor):

  • Байти, що зберігаються, не кодуються як utf8mb4. Виправте це.
  • Також перевірте, чи підключено під час читання UTF-8.

Чорні діаманти зі знаками запитання ( Se�orдля Señor); існує один із таких випадків:

Випадок 1 (оригінальні байти не були UTF-8):

  • Байти, що зберігаються, не кодуються як utf8. Виправте це.
  • З'єднання (або SET NAMES) для INSERT іSELECT НЕ utf8 / utf8mb4. Виправте це.
  • Також перевірте, чи стовпець у базі даних CHARACTER SET utf8(або utf8mb4).

Випадок 2 (оригінальними байтами були UTF-8):

  • З'єднання (або SET NAMES) для SELECTне було utf8 / utf8mb4. Виправте це.
  • Також перевірте, чи стовпець у базі даних CHARACTER SET utf8(або utf8mb4).

Чорні діаманти трапляються лише тоді, коли для браузера встановлено значення <meta charset=UTF-8>.

Знаки питання (звичайні, а не чорні діаманти) ( Se?orдля Señor):

  • Байти, що зберігаються, не кодуються як utf8 / utf8mb4. Виправте це.
  • Стовпець у базі даних не є CHARACTER SET utf8(або utf8mb4). Виправте це. (Використовуйте SHOW CREATE TABLE.)
  • Також перевірте, чи підключено під час читання UTF-8.

Mojibake ( Señorдля Señor): (Це обговорення стосується також подвійного кодування , яке не обов’язково видно.)

  • Байти, які слід зберегти, повинні мати кодування UTF-8. Виправте це.
  • Зв'язок коли INSERTingі SELECTingтекст повинен вказувати utf8 або utf8mb4. Виправте це.
  • Стовпець потрібно оголосити CHARACTER SET utf8(або utf8mb4). Виправте це.
  • HTML слід починати з <meta charset=UTF-8>.

Якщо дані виглядають правильно, але сортувати їх не вдасться правильно, то або ви вибрали неправильний метод сортування, або не існує порівняння, яке відповідає вашим потребам, або у вас є подвійне кодування .

Подвійне кодування можна підтвердити, виконавши SELECT .. HEX ..описане вище.

é should come back C3A9, but instead shows C383C2A9
The Emoji 👽 should come back F09F91BD, but comes back C3B0C5B8E28098C2BD

Тобто шестигранник приблизно вдвічі довший, ніж повинен бути. Це викликано перетворенням з latin1 (або будь-якого іншого) у utf8, потім обробкою цих байтів, ніби вони є latin1, і повторенням перетворення. Сортування (і порівняння) не працює належним чином, оскільки це, наприклад, сортування, ніби це рядок Señor.

Виправлення даних, де це можливо

Для скорочення та знаків запитання дані втрачаються.

Для Mojibake / Подвійне кодування , ...

Для Black Diamonds , ...

У скрутних перераховані тут. (5 різних виправлень для 5 різних ситуацій; обережно вибирайте): http://mysql.rjweb.org/doc.php/charcoll#fixes_for_various_cases


Якщо клієнт, база даних і таблиці знаходяться, utf8mb4я, здається, можу зберігати смайлики чудово. Деякі блоги пропонують також встановити collation-serverта character-set-serverв mysqld. Чи справді потрібно змінювати mysqldрізницю в налаштуваннях сервера?
david_adler

@david_adler - Є кілька способів отримати ефект від цих налаштувань. Найкраще - використовувати параметри підключення клієнтів. Друге найкраще, виконавши SET NAMES utf8mb4відразу після підключення. Зрештою, це декларування кодування в клієнті .
Rick James

У MySQL 8.0 (тепер випущено) за замовчуванням встановлено utf8mb4та utf8mb4_0900_ai_ci. Більшість користувачів повинні використовувати їх, не розглядаючи інші набори символів та порівняння.
Рік Джеймс,

Поради щодо налаштування Python , PHP та близько 40 інших мов
Рік Джеймс,

Ще одне зауваження: якщо задіяно FUNCTIONабо STORED PROCEDURE, можливо, ви не використовували потрібну кодировку під час її створення. DROPце SET NAMES,; повторно CREATE.
Рік Джеймс

7

У мене були подібні проблеми з 2 моїми проектами після перенесення сервера. Після пошуку та випробування багатьох рішень я натрапив на це:

mysqli_set_charset($con,"utf8");

Після додавання цього рядка до мого конфігураційного файлу все працює нормально!

Я знайшов це рішення для mysqli https://www.w3schools.com/PHP/func_mysqli_set_charset.asp, коли шукав вирішення вставки із запиту html

Щасти!


Так, це одна з кількох речей, які можуть спричинити проблеми з набором символів. Примітка: цей синтаксис дійсний для PHP, а не для інших мов додатків, і лише за умови використання mysqli, ні PDO.
Рік Джеймс,

2

Я також шукав те саме питання, на пошук відповідного рішення знадобився майже 1 місяць. Перш за все, вам доведеться оновити базу даних усіх останніх ХАРАКТЕРІВ та ЗБІРКИ до utf8mb4 або принаймні, які підтримують дані utf-8.

Для Java:

під час встановлення з'єднання JDBC додайте це до URL-адреси з'єднання useUnicode = yes & characterEncoding = UTF-8 як параметри, і воно буде працювати.

Для python:

Перед запитом до бази даних спробуйте застосувати це до курсору * cursor.execute('SET NAMES utf8mb4') cursor.execute("SET CHARACTER SET utf8mb4") cursor.execute("SET character_set_connection=utf8mb4") *

Якщо це не допомогло, щасливого полювання за правильним рішенням.


1 місяць? Це було швидко. Мені знадобився більше року, щоб сформулювати ці запитання. Java виглядає правильно. SETsне є «правильним» способом для Python; див. mysql.rjweb.org/doc.php/charcoll#python Багато інших мов обговорюються в інших місцях цього блогу.
Рік Джеймс

@RickJames Але ця проблема існує з Mysql-Python нижче 1.2.4, тому SETтвердження в основному є роботою.
Ashish Bhatt

1

Забавно, як ти відповідаєш на власне запитання :)

  1. Встановіть для мови IDE коду значення UTF8

  2. Додайте до заголовка веб-сторінки, де ви збираєте форму даних.

  3. Перевірте, як визначення таблиці MySQL виглядає так:

    CREATE TABLE your_table (
      ...
    ) ENGINE=InnoDB DEFAULT CHARSET=utf8
    
  4. Якщо ви використовуєте PDO, переконайтеся

    $options = array(PDO::MYSQL_ATTR_INIT_COMMAND=>'SET NAMES utf8'); 
    $dbL = new PDO($pdo, $user, $pass, $options);
    

Якщо у вас вже є велика база даних із зазначеною вище проблемою, ви можете спробувати SIDU експортувати за допомогою правильної кодировки та імпортувати назад за допомогою UTF8. Удачі


8
(Відповідь на власне запитання є особливістю цього форуму.) Я роками працюю над тим, щоб зробити відповідь такою короткою, проте повною.
Rick James

Таблиця DEFAULT CHARSETfor - це саме це, за замовчуванням. Це може, а іноді і повинно бути замінено на визначення стовпця.
Rick James

2
PDO краще робити з опцією $db = new PDO('dblib:host=host;dbname=db;charset=UTF8', $user, $pwd); коду : (Це вказано у посиланні на мій документ "charcoll".)
Rick James

Ви на 20 тисяч досвідченіші за мене :) Так, ви можете встановити кодировку для стовпця. Постарайтеся не використовувати надмірно. Зрештою, ви отримаєте більше часу на управління. Подібним чином ви можете надати доступ до певного стовпця таблиці MySQL. Однак вам не доведеться його використовувати, якщо у вас немає кращої альтернативи.
SIDU

2
@ppmakeitcount: ні, ALTER DATABASEзаява не вимагає перезапуску MySQL, щоб це вплинуло. Однак зміна набору символів за замовчуванням для бази даних не впливає на жодну таблицю, що на даний момент знаходиться в базі даних; це впливає лише на нові таблиці, наприклад, CREATE TABLEякі не визначають набір символів за замовчуванням для таблиці; саме тоді в гру вступає набір символів за замовчуванням. (Подібним чином, зміна набору символів за замовчуванням таблиці не впливає на стовпці, що вже є в таблиці; це впливає лише на стовпці, додані до таблиці, коли не вказаний
набір

-3

Залежно від того, як налаштовано сервер, вам доведеться відповідно змінити кодування. utf8 з того, що ви сказали, повинен працювати найкраще, однак, якщо ваші дивні символи можуть допомогти, якщо ви зміните веб-сторінку Encode на Ansi. Це допомогло мені, коли я налаштовував PHP MYSQLI, це може допомогти вам зрозуміти більше /superuser/762473/ansi-to-utf-8-in-notepad


Блокнот, ANSIмабуть, найближчий до MySQL latin1. 0x93 у цьому посиланні є і, мабуть, походить з такого місця, як Word. Ви можете або перетворити на utf8 (hex E2809C), або сказати MySQL, що дані є, latin1і сподіватися, що ви не зіткнетеся десь ще.
Рік Джеймс
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.