postgresql 匹配或转换 utf-8 变体字符串

uno*_*omi 5 postgresql collation utf-8 string-searching postgresql-13

Postgres 13

我正在寻找一种在 postgresql 中搜索可能具有变体字符表示形式的 UTF-8 文本的方法(正确的术语是什么?即vs )。life

我遇到匹配变体字符的问题,请考虑

-- This works as expected
select 'life' ilike '%life%' matches 

-- I would like to also be able to match against this source text like this
select '' ilike '%life%' matches
Run Code Online (Sandbox Code Playgroud)

请注意,有无数的变体,我此时并不特别关心与非 ascii 可表示字符的匹配,也就是说,我认为只要最终与 匹配,我就可以从 utf-8 到 ascii 有损转换life

Dan*_*ité 4

vs是 Unicode“兼容性等效”的一种情况,在UAX#15LIFE中定义为:

兼容性等效是代表相同抽象字符(或抽象字符序列)的字符或字符序列之间的较弱等效类型,但可能具有不同的视觉外观或行为。兼容性等效形式的视觉外观通常构成它们等效的字符(或字符序列)的预期视觉外观范围的子集

显式标准化方法

为了标准化兼容性等效测试,可以使用 NFKC 或 NFKD 形式。

Postgres 13 或更高版本提供了normalize以下功能:

=> select normalize('', nfkc);
 normalize 
-----------
 LIFE
Run Code Online (Sandbox Code Playgroud)

比较小写字母life和大写字母LIFE发生在不同的级别,这当然是更广为人知的。ilike可以像问题中那样使用,或者两个字符串可以使用loweror转换为相同的大小写upper

整理方式

另一种方法是使用非确定性 ICU 排序(Postgres 12 或更高版本)在“二级”进行比较。在此级别,排序规则直接考虑兼容性等效性和大小写等效性:

=> CREATE COLLATION nd2 (
  provider = 'icu',
  locale = '@colStrength=secondary', -- or 'und-u-ks-level2'
  deterministic = false
);

=> select 'life' = '' collate "nd2";
 ?column? 
----------
 t
Run Code Online (Sandbox Code Playgroud)

但是,此类排序规则不能与运算符一起使用LIKE