Postgres如何统计UTF-8多字节emoji字符串的实际显示长度
Postgres 统计emoji视觉感知字符数的可行方案
Postgres 原生length()函数统计的是Unicode码点数量,本身符合SQL标准,你要的「用户感知字符数」对应Unicode标准中的字素簇(Grapheme Cluster),无需外部语言预处理的实现方案如下:
方案1:基于正则元字符\X实现(推荐)
\X是正则语法中专用于匹配单个字素簇的元字符,分割后统计非空项即可得到视觉字符数:
- 如果你使用Postgres 12及以上版本,且数据库编译时启用了ICU支持,直接创建如下自定义函数即可:
CREATE OR REPLACE FUNCTION visible_length(input_str text) RETURNS integer AS $$ SELECT count(*) FROM regexp_split_to_table(input_str, '\X'::text) t(c) WHERE c <> ''; $$ LANGUAGE sql STABLE;
- 如果你仍在使用Postgres 11,需要先安装
pcre2扩展获得对\X元字符的支持,函数逻辑和上述完全一致。 - 效果验证:
SELECT visible_length('❤️'); -- 返回 1 SELECT visible_length('🏃♂️'); -- 返回 1 SELECT visible_length('你好World🎉'); -- 返回 8,符合视觉感知计数
方案2:自定义emoji映射表(无扩展依赖)
如果无法升级数据库、也不能安装额外扩展,可以自己维护多码点emoji映射表,先把所有多码点emoji替换为单个占位符后再计数:
-- 提前创建emoji_map表,存储所有多码点emoji的完整字符串 CREATE OR REPLACE FUNCTION visible_length_no_ext(input_str text) RETURNS integer AS $$ WITH emojis_replaced AS ( SELECT regexp_replace( input_str, (SELECT string_agg(emoji_str, '|') FROM emoji_map), ' ', 'g' ) AS processed_str ) SELECT length(processed_str) FROM emojis_replaced; $$ LANGUAGE sql STABLE;
该方案的缺点是需要随Unicode新版emoji标准更新映射表,适合emoji使用场景可控的业务。
方案3:基于内置过程语言实现
如果你的数据库开启了PL/Perl、PL/Tcl等内置过程语言支持,可以直接调用语言本身的字素簇计数能力,以PL/Perl为例:
CREATE OR REPLACE FUNCTION visible_length_plperl(input_str text) RETURNS integer AS $$ use Unicode::GCString; return Unicode::GCString->new($_[0])->length; $$ LANGUAGE plperl STABLE;
内容的提问来源于stack exchange,提问作者metalaureate
相关产品推荐
相关产品推荐

