如何沿UTF-16码点走?

时间:2016-01-29 23:53:59

标签: c++ unicode utf-16

我有以下与代码点和代理对相对应的变化范围的定义:

https://en.wikipedia.org/wiki/UTF-16#Description

我的代码基于Clang implementation中的ConvertUTF.c

我目前正在努力解决如何做到这一点。

与我想要了解的LLVM实现最相关的代码是:

unsigned short bytesToWrite = 0;
const u32char_t byteMask = 0xBF;
const u32char_t byteMark = 0x80; 
u8char_t* target = *targetStart;

utf_result result = kConversionOk;
const u16char_t* source = *sourceStart;
while (source < sourceEnd) {
   u32char_t ch;
   const u16char_t* oldSource = source; /* In case we have to back up because of target overflow. */
   ch = *source++;
   /* If we have a surrogate pair, convert to UTF32 first. */
   if (ch >= UNI_SUR_HIGH_START && ch <= UNI_SUR_HIGH_END) {
      /* If the 16 bits following the high surrogate are in the source buffer... */
      if (source < sourceEnd) {
         u32char_t ch2 = *source;
         /* If it's a low surrogate, convert to UTF32. */
         if (ch2 >= UNI_SUR_LOW_START && ch2 <= UNI_SUR_LOW_END) {
            ch = ((ch - UNI_SUR_HIGH_START) << halfShift)
               + (ch2 - UNI_SUR_LOW_START) + halfBase;
            ++source;
         } else if (flags == kStrictConversion) { /* it's an unpaired high surrogate */
            --source; /* return to the illegal value itself */
            result = kSourceIllegal;
            break;
         }
      } else { /* We don't have the 16 bits following the high surrogate. */
         --source; /* return to the high surrogate */
         result = kSourceExhausted;
         break;
      }
   } else if (flags == kStrictConversion) {
      /* UTF-16 surrogate values are illegal in UTF-32 */
      if (ch >= UNI_SUR_LOW_START && ch <= UNI_SUR_LOW_END) {
         --source; /* return to the illegal value itself */
         result = kSourceIllegal;
         break;
      }
   }
   ...

具体来说,他们在评论中说:

  

如果我们有代理项对,请先转换为UTF32。

然后:

  

如果它是低代理,请转换为UTF32。

我迷失了“如果我们......”和“如果它......”以及我在阅读评论时的回答:“我们有什么?”和“它是什么?”

我相信chch2是第一个char16和下一个char16(如果存在),检查第二个是否是代理对的一部分,然后沿着每个char16走(或者你沿着一对字符走路?)直到最后。

我迷失了他们如何使用UNI_SUR_HIGH_STARTUNI_SUR_HIGH_ENDUNI_SUR_LOW_STARTUNI_SUR_LOW_END以及他们使用halfShifthalfBase

维基百科还指出:

  

由于数字值与其名称不匹配,有人试图将“高”和“低”代理重命名为“领先”和“尾随”。这似乎在最近的Unicode标准中被放弃了。

在任何回复中记下“领先”和“尾随”也可能有助于澄清事情。

1 个答案:

答案 0 :(得分:2)

ch >= UNI_SUR_HIGH_START && ch <= UNI_SUR_HIGH_END检查ch是否在高代理范围内,即[D800-DBFF]。而已。然后做同样的事情来检查ch2是否在低代理范围内,意味着[DC00-DFFF]。

halfShifthalfBase只是按照UTF-16解码算法的规定使用,它将一对代理转换为它们代表的标量值。这里没有什么特别的事情;它是该算法的教科书实现,没有任何技巧。