2011-01-05 101 views
9

我必须通过一些文本并根据字符模式编写UTF8输出。如果我可以使用代码点并将其转换为UTF8,我认为这很容易。我一直在阅读unicode和UTF8,但找不到一个好的解决方案。任何帮助将不胜感激。C库将unicode代码点转换为UTF8?

回答

33

转换Unicode代码点为UTF-8是如此的微不足道的是,制造调用库可能需要的不仅仅是自己做更多的代码:

if (c<0x80) *b++=c; 
else if (c<0x800) *b++=192+c/64, *b++=128+c%64; 
else if (c-0xd800u<0x800) goto error; 
else if (c<0x10000) *b++=224+c/4096, *b++=128+c/64%64, *b++=128+c%64; 
else if (c<0x110000) *b++=240+c/262144, *b++=128+c/4096%64, *b++=128+c/64%64, *b++=128+c%64; 
else goto error; 

而且,做你自己意味着你可以调整的API来w的类型你需要的ork(角色在一次?或长字符串?)如果您知道输入是有效的Unicode标量值,则可以删除错误情况。

另一个方向很难得到正确的。我推荐一种有限自动机方法,而不是典型的位算术循环,有时将无效序列解码为真实字符的别名(这非常危险并且可能导致安全问题)。我认为你应该先尝试自己编写它,或者至少在进一步学习之前认真研究UTF-8规范。很多糟糕的设计可能来自将UTF-8当作黑匣子来处理,当整个观点认为它不是黑匣子,而是被创建为具有非常强大的属性时,许多新的UTF-8编程人员直到看不到他们自己也一直在努力。

+6

@Philipp:是否编写了更多的代码来封装一个库,以满足您的界面需求并更好地解决其错误?如果你关心浏览解码UTF-8的现有库代码,你会发现绝大多数在错误的方面是错误的,至少30%有严重的安全关键错误。 (这些估计值来自我之前做过的Google代码搜索。)另外,'iconv'的GNU实现对于字符一次转换来说速度太慢了,尽管它可以正常工作(尽管有意不符合)进行批量转换。 – 2011-01-06 16:08:28

+0

我在更高级的版本中拍摄:http://mercurial.intuxication.org/hg/cstuff/raw-file/tip/utf8_encode.c – Christoph 2011-01-06 20:47:51

+2

拒绝非字符可能对您的应用程序有用,但它不是UTF-8规范和一般不正确。 UTF是代码单元序列(字节或更大的单词)与“Unicode标量值”之间的一对一映射。 Unicode标量值正好是整数0-0xD7FF和0xE000-0x10FFFF。这一切都是在Unicode标准中定义的,你应该在尝试实现自己的东西之前阅读它。 – 2011-01-06 21:37:40

1

哪个平台?在Windows上,您可以使用WideCharToMultiByte(CP_UTF8,...)

可以说,源代码点必须用UTF-16编码,这意味着您必须能够执行此类编码。在某些情况下(代理对),这不是微不足道的。

我的理解是,您在给定的代码页中有一些文本,并且您想将其转换为Unicode(UTF-16)。对?一个MultiByteToWideChar(codePage,sourceText,...)/ WideCharToMultiByte(CP_UTF8,utf16Text,...)往返就可以实现。

+0

我正在使用linux。 – chanux 2011-01-06 03:04:23

+0

@chanux:然后您可以使用'iconv',如其他答案中所述。 – Philipp 2011-01-06 10:53:25

5

iconv可以用我图。

#include <iconv.h> 

iconv_t cd; 
char out[7]; 
wchar_t in = CODE_POINT_VALUE; 
size_t inlen = sizeof(in), outlen = sizeof(out); 

cd = iconv_open("utf-8", "wchar_t"); 
iconv(cd, (char **)&in, &inl, &out, &outlen); 
iconv_close(cd); 

但我担心的wchar_t可能不代表Unicode代码点,但任意值..编辑:我想你可以通过简单地用一个Unicode源做到这一点:

uint16_t in = UNICODE_POINT_VALUE; 
cd = iconv_open("utf-8", "ucs-2"); 
+2

如果代码点不在BMP中,该怎么办? ucs-2无法表示它。根据平台,一个wchar_t可能不够。这就是为什么我认为OP关于了解代码点的假设是错误的。因为这样,就会询问用于表示它的编码问题(UTF-32?UTF-16?显然不是UTF-8) – 2011-01-05 18:15:56

+1

如果定义了__STDC_ISO_10646__,则wchar_t是Unicode码值。请注意,如果'wchar_t'是16位,这意味着只支持BMP; UTF-16不是一种可能性。 – 2011-01-05 22:56:42

+1

16位'wchar_t'可以明确用于UTF-16编码的字符串。所有这一切都意味着,BMP以外的任何代码点值将使用2个'wchar_t'替代字符并排编码的字符串进行编码,就这些了。 Windows API正好运行在这种类型的数据上,并且它工作得很好。 – 2011-01-09 09:31:19