首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >UTF8编解码与长度

UTF8编解码与长度
EN

Code Review用户
提问于 2016-09-20 22:05:52
回答 1查看 640关注 0票数 7

我需要一个能:

  • 解码并返回UTF8编码字符串中的第一个字符
  • '\0'长度必须为0的特例返回编码长度
  • 成绩是很重要的

对于如何处理无效序列,我没有特别的要求,因此我选择了以下行为:

  • 无效序列的第一个字节被视为单个“字符”(例如,对于序列"\xFF\x2F",它将返回'\xFF'作为值,1作为长度)。
  • 接受超长编码

我编写了以下函数:

代码语言:javascript
复制
static uint8_t LEN[] = {1,1,1,1,2,2,3,0};
static uint8_t MSK[] = {0,0,3,4,5,0,0,0};

static int utf8_cp(char *txt, int32_t *ch)
{
  int len = 0;
  int32_t val = 0;
  uint8_t first = (uint8_t)(*txt);

  len = (first > 0) * (1 + ((first & 0xC0) == 0xC0) * LEN[(first >> 3) & 7]);
  val = first & (0xFF >> MSK[len]);

  for (int k=len; k>1; k--) {
    if ((*++txt & 0xC0) != 0x80) {
      val = first;
      len = 1;
      break;
    }
    val = (val << 6) | (*txt & 0x3F);
  }

  *ch = val;
  return len;
}

所以这样的代码:

代码语言:javascript
复制
char *t; int l; int32_t c;

t = "aàも";
while(1) {
  l = utf8_cp(t, &c);
  printf("'%s' len:%d cp:0x%05x\n", t, l, c);
  if (*t == 0) break;
  t += l;
} 

生产:

代码语言:javascript
复制
'aàも' len:1 cp:0x00061
'àも' len:2 cp:0x000e0
'も' len:3 cp:0x03082
'' len:4 cp:0x2b014
'' len:0 cp:0x00000

为了使它更快,我考虑了展开for循环(但我想知道我能得到多少),并在开始时引入一些if来处理ASCII字符(但我担心分支比做一堆操作代价更高)。

我将感谢您的任何意见和任何改进建议。

EN

回答 1

Code Review用户

回答已采纳

发布于 2016-09-21 01:44:47

不要使用狭窄的类型,而是使用最快的类型。

代码语言:javascript
复制
// uint8_t first = (uint8_t)(*txt);
unsigned first = (uint8_t)(*txt);
// or
uint_fast8_t first = (uint8_t)(*txt);

与其查找要移位的值,不如向上查找移位的值。

代码语言:javascript
复制
// static uint8_t MSK[] = {0,0,3,4,5,0,0,0};
//  val = first & (0xFF >> MSK[len]);

static const uint8_t FF_MSK[] = {0xFF >>0, 0xFF >>0, 0xFF >>3, 
    0xFF >>4, 0xFF >>5, 0xFF >>0, 0xFF >>0, 0xFF >>0};
val = first & FF_MSK[len];

如果已知指针不重叠,一些现代编译器可以进行额外的优化--在适用的情况下使用restrictconst

代码语言:javascript
复制
// int utf8_cp(char *txt, int32_t *ch)
int utf8_cp(const char * restrict txt, int32_t *restrict ch)

编写配套函数将有助于对这两个函数进行测试。

代码语言:javascript
复制
int utf8_cp_encode(int32_t *ch, char *txt);

由于代码不会检测到max_Unicode上的代理、冗余模式和值等无效编码,所以我认为只处理无效序列的子集没有什么价值。要么检测它们全部(可能处于调试模式),要么跳过检测。

建议进行32字节(或256字节)的查找以提高性能。找出最佳配置文件。

代码语言:javascript
复制
// len = (first > 0) * (1 + ((first & 0xC0) == 0xC0) * LEN[(first >> 3) & 7]);
len = (first > 0) * LEN_32[first >> 3];
// or
len = LEN_256[first];

可以将上面的内容扩展到对lenval进行一次查找。

票数 4
EN
页面原文内容由Code Review提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://codereview.stackexchange.com/questions/141975

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档