Есть ли многобайтовый Postgresql Левенштейн?

Когда я использую функцию fuzzystrmatch Левенштейна с диакритическими символами, она возвращает неверный / многобайтовый невежественный результат:

select levenshtein('ą', 'x');
levenshtein 
-------------
       2

(Примечание: первый символ - это "а" с диакритическим знаком ниже, он не отображается должным образом после того, как я скопировал его здесь)

Документация по fuzzystrmatch ( https://www.postgresql.org/docs/9.1/fuzzystrmatch.html) предупреждает, что:

В настоящее время функции soundex, metaphone, dmetaphone и dmetaphone_alt плохо работают с многобайтовыми кодировками (такими как UTF-8).

Но так как она не называет функцию Левенштейна, мне было интересно, существует ли многобайтовая версия Левенштейна.

Я знаю, что я мог бы использовать функцию unaccent в качестве обходного пути, но я должен держать диакритические знаки.

1 ответ

Решение

Примечание: это решение было предложено @Nick Barnes в его ответе на связанный вопрос.

'A' с диакритическим знаком представляет собой последовательность символов, то есть комбинацию символов a и символа объединения, диакритический знак ̨: E'a\u0328'

Существует эквивалентный предварительно составленный символ ą: E'\u0105'

Решением было бы нормализовать строки Unicode, то есть преобразовать объединяющую последовательность символов в предварительно составленный символ перед их сравнением.

К сожалению, в Postgres, похоже, нет встроенной функции нормализации Unicode, но вы легко можете получить к ней доступ через расширения языка PL/Perl или PL/Python.

Например:

create extension plpythonu;

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

Теперь, как последовательность символов E'a\u0328' отображается на эквивалентный предварительно составленный символ E'\u0105' используя unicode_normalize, расстояние Левенштейна является правильным:

select levenshtein(unicode_normalize(E'a\u0328'), 'x');
levenshtein
-------------
           1
Другие вопросы по тегам