我有一个嵌入式系统,可以通过UPNP显示UTF-8编码数据。显示设备具有显示字符的能力。我需要一种方法将我通过UPNP接收的UTF-8数据转换为unicode。显示在PIC上,它通过运行linux的UPNP桥发送数据。在将其发送到linux中的显示板之前,是否有一种简单的方法进行转换?
答案 0 :(得分:1)
将编码为UFT-8的字节数组转换为Unicode代码点数组:
诀窍是检测各种编码错误。
#include <limits.h>
#include <stdio.h>
#include <stdbool.h>
#include <stdint.h>
typedef struct {
uint32_t UnicodePoint; // Accumulated code point
uint32_t Min; // Minimum acceptable codepoint
int i; // Index of char/wchar_t remaining
bool e; // Error flag
} UTF_T;
static bool IsSurrogate(unsigned c) {
return (c >= 0xD800) && (c <= 0xDFFF);
}
// Return true if more bytes needed to complete codepoint
static bool Put8(UTF_T *U, unsigned ch) {
ch &= 0xFF;
if (U->i == 0) {
if (ch <= 0x7F) {
U->UnicodePoint = ch;
return false; /* No more needed */
} else if (ch <= 0xBF) {
goto fail;
} else if (ch <= 0xDF) {
U->Min = 0x80;
U->UnicodePoint = ch & 0x1F;
U->i = 1;
} else if (ch <= 0xEF) {
U->Min = 0x800;
U->UnicodePoint = ch & 0x0F;
U->i = 2;
} else if (ch <= 0xF7) {
U->Min = 0x10000;
U->UnicodePoint = ch & 0x07;
U->i = 3;
} else {
goto fail;
}
return true; /* More needed */
}
// If expected continuation character missing ...
if ((ch & (~0x3F)) != 0x80) {
goto fail;
}
U->UnicodePoint <<= 6;
U->UnicodePoint |= (ch & 0x3F);
// If last continuation character ...
if (--(U->i) == 0) {
// If codepoint out of range ...
if ((U->UnicodePoint < U->Min) || (U->UnicodePoint > 0x10FFFF)
|| IsSurrogate(U->UnicodePoint)) {
goto fail;
}
return false /* No more needed */;
}
return true; /* More needed */
fail:
U->UnicodePoint = -1;
U->i = 0;
U->e = true;
return false /* No more needed */;
}
/* return 0:OK, else error */
bool ConvertUTF8toUnicodeCodepoints(const char *UTF8, size_t Length,
uint32_t *CodePoints, size_t *OutLen) {
UTF_T U = { 0 };
*OutLen = 0;
for (size_t i = 0; i < Length;) {
while (Put8(&U, UTF8[i++])) {
// Needed bytes not available?
if (i >= Length) {
return true;
}
}
if (U.e) break;
CodePoints[(*OutLen)++] = U.UnicodePoint;
}
return U.e;
}
这是基于一些旧代码,请提供建议,因为它可能不符合现行标准
goto
和魔术数字不是最漂亮的。
这种方法的好处在于消耗代码点而不是CodePoints[(*OutLen)++] = U.UnicodePoint
,如果想要提取UTF16(BE或LE),可以轻松编写UTF_T
块的消费者代码而不是需要改为UTF8 - &gt;代码点部分。
答案 1 :(得分:1)
如果您拥有真实的操作系统和托管的C环境,最好的方法是确保您的程序在使用UTF-8作为其编码的语言环境中运行并使用mbrtowc
或{ {1}}将UTF-8序列转换为Unicode代码点值(mbtowc
是Linux上的Unicode代码点编号以及定义wchar_t
)的任何C实现。
如果您想跳过系统库例程并自己进行UTF-8解码,请注意。我曾经使用谷歌代码搜索做了一个随意的调查,发现在野外的1/3到2/3之间的UTF-8代码是危险的错误。这是一个完全正确,快速,简单的实现,我强烈推荐:
http://bjoern.hoehrmann.de/utf-8/decoder/dfa/
My implementation in musl的二进制大小有点小,似乎更快,但它也有点难以理解。
答案 2 :(得分:0)
我会使用GLIB的Unicode manipulation functions,这是一个LGPL许可的实用程序库。听起来g_utf8_to_ucs4()就像你要找的那样。