按字节截取文本

来自 PostgreSQL Wiki
跳转到导航跳转到搜索

库代码片段

按字节宽度截取 UTF-8 文本

适用于 PostgreSQL

任何版本

PL/pgSQLl

依赖于


有几种不同的方法可以将使用 UTF-8 或其他可变编码方法编码的字符串/文本截取到指定的字节宽度。



方法 1:作者 Laruenz Albe 实现了 SQL,它生成一个包含表中所有可能的字节长度到字符长度的记录集,然后过滤结果。

CREATE OR REPLACE FUNCTION get_prefix (
   string text,
   max_bytes bigint
) RETURNS text
   LANGUAGE sql STRICT AS
$$SELECT p
FROM (SELECT p.p, octet_length(p.p) AS len
      FROM generate_series(0, length($1)) AS len
         CROSS JOIN LATERAL substr($1, 1, len.len) AS p) AS q
WHERE len <= $2
ORDER BY len DESC
LIMIT 1$$;



方法 2:作者 Zsheep 实现了 PLpg/SQL,它从左到右逐个字符迭代字符串,直到字符串的字节宽度大约等于输入宽度。

Create or Replace function max_bytea_length(pchars text, bytea_length int)
RETURNS bytea
LANGUAGE plpgsql

COST 100
VOLATILE 
AS $BODY$

declare 
_i int;
_length_of_chars int;
_newchars text;
_testchars text;
begin

if octet_length(pchars::bytea) <= bytea_length then
   return pchars::bytea;
end if;
_i = least( octet_length(pchars)-4, bytea_length-4);
_length_of_chars =  char_length(pchars);
loop 
   _newchars= left(pchars, _i);
    _testchars = left(pchars, _i+1); 
  if octet_length(_testchars::bytea) > bytea_length or _i = _length_of_chars  then
     return _newchars::bytea;
  end if ;
  _i = _i+1;
end loop ;

end;
$BODY$



方法 3:作者 Daniel Veritte 实现了 SQL 函数,它检查 UTF-8 字节序列,查找小于或等于最大字节宽度的最高字节。

create function utf8_truncate(str text, len int) returns text
as $$
select case when octet_length(str) <= len then str
else (
   with bstr(s) as (select convert_to(str, 'UTF-8'))
   select
   case
   when len>=1 and (get_byte(s, len) & 192) <> 128
   then convert_from(substring(s, 1, len), 'UTF-8')
   else
     case
     when len>=2 and (get_byte(s, len-1) & 192) <> 128
     then convert_from(substring(s, 1, len-1), 'UTF-8')
     else
       case
       when len>=3 and (get_byte(s, len-2) & 192) <> 128
       then convert_from(substring(s, 1, len-2), 'UTF-8')
       else
         case
         when len>=4 and (get_byte(s, len-3) & 192) <> 128
         then convert_from(substring(s, 1, len-3), 'UTF-8')
         else ''
         end
       end
     end
   end
 from bstr)
   end;
$$ language sql strict immutable parallel safe;


用法示例

SELECT get_prefix('abc€', 4);

select max_bytea_length('i ♥ u function changed it to be faster', 56);

select utf8_truncate('method 3 €', 9);