Есть ли многобайтовый Postgresql Левенштейн? - PullRequest
2 голосов
/ 20 июня 2019

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

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

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

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

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

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

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

1 Ответ

1 голос
/ 21 июня 2019

Примечание: это решение было предложено @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
...