Нормализация Юникода в Postgres

У меня есть большое количество имен шотландских и валлийских акцентированных мест (сочетающих тяжелые, острые, округлые и диаресты), которые мне нужно обновить до их нормализованной формы в Юникоде, например, более короткая форма 00E1 (\ xe1) для á вместо 0061 + 0301 (\ x61\x301)

Я нашел решение из старого почтового списка Postgres nabble с 2009 года, используя pl/python,

create or replace function unicode_normalize(str text) returns text as $$
  import unicodedata
  return unicodedata.normalize('NFC', str.decode('UTF-8'))
$$ LANGUAGE PLPYTHONU;

Это работает, как и ожидалось, но заставило меня задаться вопросом, есть ли способ сделать это непосредственно со встроенными функциями Postgres. Я пробовал различные преобразования, используя convert_to, все напрасно.

EDIT: Как заметил Крейг, и одна из вещей, которые я пробовал:

SELECT convert_to(E'\u00E1', 'iso-8859-1');

возвращает \xe1, тогда как

SELECT convert_to(E'\u0061\u0301', 'iso-8859-1');

не работает с ERROR: character 0xcc81 of encoding "UTF8" has no equivalent in "LATIN1"

Ответы

Ответ 1

Я думаю, что это ошибка Pg.

PostgreSQL должен нормализовать utf-8 в предварительно сформированную форму перед выполнением преобразований кодирования. Результат показанных преобразований неверен.

Я подниму его на pgsql-bugs... сделаю.

http://www.postgresql.org/message-id/[email protected]

Вы должны быть в состоянии следить за ним.

BTW, это можно упростить до:

regress=> SELECT 'á' = 'á';
 ?column? 
----------
 f
(1 row)

который является простым безумным разговором, но разрешен. Первый предварительно скомпонован, второй - нет. (Чтобы увидеть этот результат, вам придется копировать и вставлять его, и он будет работать, только если ваш браузер или терминал не нормализуют utf-8).

Если вы используете Firefox, вы можете не видеть выше правильно; Chrome делает это правильно. Здесь вы должны увидеть, правильно ли ваш браузер обрабатывает Unicode:

Decomposed vs precomposed unicode á showing false for equality