Как я могу хранить символы UTF-16 в базе данных Postgres?

Я пытаюсь сохранить текст (например, č) в базе данных Postgres, однако при получении этого значения оно отображается на экране как ?, Я не уверен, почему это происходит, у меня сложилось впечатление, что это был персонаж, который не был поддержан в UTF-8, но был в UTF-8, однако, судя по первому ответу, это неверное предположение,

Оригинальный вопрос (который все еще может быть действительным):

Я читал о суррогатных парах UTF-8, которые могут достичь того, что мне нужно, и я видел несколько примеров, включающих stringinfo объект TextElementEnumerators, но я не смог выработать практическое подтверждение концепции.

Может кто-нибудь привести пример того, как вы будете писать и читать UTF-16 (возможно, с использованием этой концепции суррогатных пар) в базу данных postgres. Спасибо.

Обновленный вопрос: почему бы č символ будет возвращен из базы данных в виде знака вопроса?

Мы используем NPGSQL для доступа к базе данных и VB.Net.

1 ответ

Решение

Нет такой вещи как персонаж, который существует в UTF-16, но не в UTF-8. Оба способны кодировать все Unicode. Другими словами, если вы можете заставить UTF-8 работать, он должен иметь возможность хранить любой допустимый текст Unicode.

РЕДАКТИРОВАТЬ: Суррогатные пары на самом деле являются особенностью UTF-16, а не UTF-8. Они позволяют символу, который не находится в основной многоязычной плоскости (BMP), быть представленными как две кодовые единицы UTF-16. По сути, UTF-16 часто рассматривается как кодирование с фиксированной шириной (ровно два байта на символ Unicode), но это позволяет только правильно кодировать BMP. Суррогатные пары - это (довольно хакерский) способ расширить диапазон за пределы BMP.

Я очень сомневаюсь, что персонаж, которого вы пытаетесь представить, находится за пределами BMP, поэтому я подозреваю, что вам нужно искать проблему в другом месте. В частности, стоит сбросить точные символьные значения текста (например, char в int) до того, как он попадет в базу данных и после того, как вы его загрузите. В идеале, сделать это в коротком, но полном консольном приложении.

Как я могу сохранить все "символы" UTF-16 в базе данных Postgres?

Короткий ответ: это невозможно напрямую, так как PostgreSQL поддерживает только набор символов UTF-8.

Форматы на основе UTF-16, такие как Java, JavaScript, Windows, могут содержать половинные суррогатные пары, которые не представлены в UTF-8 или UTF-32. Они могут быть легко созданы путем подстроки строки Java, JavaScript, VB.Net. Поскольку они не могут быть представлены в UTF-8 или UTF-32 и, следовательно, не могут быть сохранены в базе данных, которая поддерживает только набор символов UTF-8, такой как PostgreSQL.

Имена путей Windows могут содержать половину суррогатных пар, которые не могут быть прочитаны как utf-8 ( https://github.com/rust-lang/rust/issues/12056).

Можно было бы использовать систему баз данных, которая поддерживает набор символов UTF-16/CESU-8, который более адаптирован к Java/Android, JavaScript/NodeJS, .Net/wchar_t/ языкам / платформам Windows. (SQLServer, Oracle (сопоставление UTF-8), DB2, Informix, HANA, SQL Anywhere, MaxDB обычно поддерживают такую ​​кодировку.

Обратите внимание, что с помощью смайликов, представляемых в виде кодовых точек Юникода вне Базовой многоязычной плоскости, эти различия станут более актуальными и для западных пользователей.

На postgres вы можете: a) принять потери, b) сохранить данные в виде двоичных данных или c) преобразовать их в закодированное представление (например, код JSON rfc кодирует их как два экранированных символа, чтобы иметь возможность транспортировать половину суррогатов в UTF-8/ Сетевой формат на основе Ascii без потерь ( https://tools.ietf.org/html/rfc4627 раздел 2.5).

Например, если смайлики находятся за пределами основного многоязычного плана, эта проблема станет более актуальной и в западном мире.

В зависимости от выбора языка сервера приложений ( Java,Scala, C#/Windows, JavaScript/NodeJS) и уровня инвестиций в языковую поддержку (с использованием, например, функций разделения строк ICU на границах графемы ( https://www.unicode.org/reports/tr29/), вместо простого усечения проблема может быть менее актуальной, но большинство корпоративных систем и языков сегодня попадают в лагерь UTF-16 с программным обеспечением, использующим простые операции с подстрокой.

Что касается проблемы хранения / извлечения č

  1. Проверьте набор символов, на котором работает база данных Postgre, это набор символов UTF-8 ( https://www.postgresql.org/docs/9.1/multibyte.html) или набор символов, который может представлять символ.

  2. Убедитесь, что клиентское соединение с базой данных настроено для выполнения соответствующего преобразования кодовой страницы (для VB.Net это будет от UTF-16LE до UTF-8 или кодировки базы данных, обычно это параметр в строке подключения (кодировка)).

  3. Убедитесь, что вход является фактической последовательностью байтов UTF-8 / UTF-16 в VB.net, а не последовательностью байтов Windows-1250.

  4. Убедитесь, что это не просто ограничение средства вывода или консоли (например, консоль Windows обычно не отображает символы Юникода, но использует набор символов Windows-12xx (можно попробовать https://superuser.com/questions/269818/change-default-code-page-of-windows-console-to-utf-8), но обычно лучше проверять последовательность байтов в отладчике VB.Net.

  5. Убедитесь, что длина столбца CHAR/VARCHAR достаточна для хранения вашего представления, даже если оно представлено в разложении NFKD.

Графема, которую вы указываете, имеет несколько разных представлений юникода.

 U+010D LATIN SMALL LETTER C WITH CARON
 U+0063 LATIN SMALL LETTER c followed by U+030C COMBINING CARON

И другие представления других наборов символов (например, 0xE8 в ISO-8859-2 / Windows-1250 ( https://en.wikipedia.org/wiki/Windows-1250) или ISO-8859-13 /Windows-1257.

Все представления Unicode попадают в базовую многоязычную плоскость, поэтому суррогатная проблема UTF-16 с postgre, как указано в заголовке вопроса и дано ответ на вопрос ниже, скорее всего, не имеет отношения к вашей проблеме.

Другие вопросы по тегам