Как я могу хранить символы 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 с программным обеспечением, использующим простые операции с подстрокой.
Что касается проблемы хранения / извлечения č
Проверьте набор символов, на котором работает база данных Postgre, это набор символов UTF-8 ( https://www.postgresql.org/docs/9.1/multibyte.html) или набор символов, который может представлять символ.
Убедитесь, что клиентское соединение с базой данных настроено для выполнения соответствующего преобразования кодовой страницы (для VB.Net это будет от UTF-16LE до UTF-8 или кодировки базы данных, обычно это параметр в строке подключения (кодировка)).
Убедитесь, что вход является фактической последовательностью байтов UTF-8 / UTF-16 в VB.net, а не последовательностью байтов Windows-1250.
Убедитесь, что это не просто ограничение средства вывода или консоли (например, консоль Windows обычно не отображает символы Юникода, но использует набор символов Windows-12xx (можно попробовать https://superuser.com/questions/269818/change-default-code-page-of-windows-console-to-utf-8), но обычно лучше проверять последовательность байтов в отладчике VB.Net.
Убедитесь, что длина столбца 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, как указано в заголовке вопроса и дано ответ на вопрос ниже, скорее всего, не имеет отношения к вашей проблеме.