截断UTF-8字符串以适合PHP中的给定字节数

6 php string unicode truncate utf-8

假设我们有一个UTF-8字符串$s,我们需要缩短它,以便它可以存储在N个字节中.盲目地将其截断为N个字节可能会搞砸它.但解码它以找到字符边界是一种拖累.有一个整洁的方式吗?

[编辑20100414]除了S.Mark的回答:mb_strcut(),我最近还发现了另一个完成这项工作的功能:grapheme_extract($s, $n, GRAPHEME_EXTR_MAXBYTES);来自intl扩展.由于intl是一个ICU包装器,我对它很有信心.

Mic*_*rdt 11

编辑: S.Mark的答案实际上比我的好 - PHP有一个(记录严重的)内置函数,可以解决这个问题.

原始的"回到位"答案如下:

  • 截断所需的字节数
  • 如果最后一个字节以110(二进制)开头,则也将其丢弃
  • 如果倒数第二个字节以1110(二进制)开头,则丢弃最后2个字节
  • 如果倒数第三个字节以11110(二进制)开头,则丢弃最后3个字节

这可以确保您没有在末尾悬挂不完整的字符,这是截断UTF-8时可能出错的主要问题.

不幸的是(正如安德鲁在评论中提醒我的那样),也有两个单独编码的Unicode代码点形成单个字符的情况(基本上,重音符号等变音符号可以表示为修改前一个字母的单独代码点).

处理这种事情需要高级的Unicode-Fu,这在PHP中是不可用的,甚至可能不适用于所有情况(那里有很多奇怪的脚本!),但幸运的是它相对罕见,至少对于基于拉丁语的语言.

  • 您应该注意的一件事是"分解形式",这意味着如果您使用此方案,您最终可能会从结果字符串中的最后一个字母丢失重音.请参阅:http://en.wikipedia.org/wiki/UTF-8#Precomposition_and_Decomposition (2认同)

YOU*_*YOU 7

我认为你不需要重新发明轮子,你可以使用mb_strcut并确保首先将编码设置为UTF-8.

mb_internal_encoding('UTF-8');
echo mb_strcut("\xc2\x80\xc2\x80", 0, 3); //from index 0, cut 3 characters.
Run Code Online (Sandbox Code Playgroud)

它的回归

\xc2\x80
Run Code Online (Sandbox Code Playgroud)

因为在\ xc2\x80\xc2中,最后一个无效

  • 它的工作原理应该是:`mb_strcut('áéíóú',0,4,'UTF-8'); //áé`和`strlen(mb_strcut('áéíóú',0,4,'UTF-8')); // 4` (2认同)