跨平台C应用程序支持UTF8

我正在开发一个跨平台C(C89标准)应用程序,它必须处理UTF8文本。我只需要基本的字符串操作函数,如
substr
first
last
等。 问题1 是否有UTF8库实现了上述功能?我已经看过ICU了,这对我的要求来说太大了。我只需要支持UTF8。 我在这里找到了一个UTF8解码器。以下函数原型来自该代码。
void utf8_decode_init(char p[], int length);

int utf8_decode_next();
初始化函数采用字符数组,但
utf8_decode_next()
返回
int
。这是为什么?如何使用
printf
等标准函数打印此函数返回的字符?该函数正在处理字符数据以及如何将其分配给整数? 如果上述解码器不适合生产代码,你有更好的推荐吗? 问题2 通过阅读文章说我也很困惑,对于unicode,你需要使用
wchar_t
。根据我的理解,这不是必需的,因为普通的C字符串可以保存UTF8值。我通过查看SQLite和git的源代码验证了这一点。 SQLite具有以下typedef。
typedef unsigned char u8
我的理解是否正确?为什么还需要
unsigned char
?     
已邀请:
utf_decode_next()
函数返回下一个Unicode代码点。由于Unicode是一个21位字符集,它不能返回小于
int
的任何东西,并且可以认为从技术上讲,它应该是
long
,因为
int
可能是16位数量。实际上,该函数会返回UTF-32字符。 您需要查看C89的C94宽字符扩展名以打印宽字符(
wprintf()
<wctype.h>
<wchar.h>
)。但是,单独的宽字符不能保证是UTF-8甚至是Unicode。您很可能无法从
utf8_decode_next()
打印字符,但这取决于您的可移植性要求。您必须移植的系统范围越广,所有工作的可能性就越小。如果您可以移植地编写UTF-8,您可以将UTF-8字符串(不是从
utf8_decode_next()
获得的UTF-32字符数组)发送到常规打印功能之一。 UTF-8的优点之一是它可以被很大程度上无知的代码操纵。 您需要了解一个4字节的
wchar_t
可以在一个单元中保存任何Unicode代码点,但UTF-8可能需要一到四个8位字节(1-4个存储单元)来保存单个Unicode代码点。在某些系统上,我相信
wchar_t
可以是一个16位(
short
)整数。在这种情况下,您被迫使用UTF-16,它使用两个存储单元和代理编码基本多语言平面(BMP,代码点U + 0000 .. U + FFFF)之外的Unicode代码点。 使用
unsigned char
让生活更轻松;平原
char
经常签名。负数会使生活变得比我需要的更困难(而且,相信我,如果不增加复杂性就很难)。     
使用UTF-8进行字符或子字符串搜索时,不需要任何特殊的库例程。
strstr
做你需要的一切。这就是UTF-8的全部要点以及它为满足而发明的设计要求。     
GLib具有相当多的相关功能,可以独立于GTK +使用。     
Unicode中有超过100,000个字符。在大多数C实现中,有25623ѭ的256个可能值。 因此,UTF-8使用多于一个
char
来编码每个字符,并且解码器需要一个大于
char
的返回类型。
wchar_t
是比
char
更大的类型(嗯,它不必更大,但通常是)。它表示实现定义的宽字符集的字符。在某些实现中(最重要的是,Windows,对于“基本多语言平面”之外的字符使用代理对),它仍然不足以表示任何Unicode字符,这可能是您引用的解码器使用
int
的原因。 你不能使用
printf
打印宽字符,因为它处理
char
wprintf
交易
wchar_t
,所以如果宽字符集是unicode,并且如果系统上的
wchar_t
int
(因为它在linux上),那么
wprintf
和朋友将打印解码器输出而无需进一步处理。否则它不会。 在任何情况下,您都无法移植打印任意unicode字符,因为无法保证终端可以显示它们,甚至不能保证宽字符集与Unicode有任何关联。 SQLite可能使用了
unsigned char
,因此: 他们知道签名 - 它的实现 - 定义是否签署了
char
。 他们可以进行右移并分配超出范围的值,并在所有C实现中获得一致且定义的结果。实施有更多自由
signed char
的表现比
unsigned char
。     
普通C字符串适用于存储utf8数据,但您无法在utf8字符串中轻松搜索子字符串。这是因为使用utf8编码编码为字节序列的字符可以是1到4个字节的任何位置,具体取决于字符。即“字符”不等同于utf8的“字节”,就像它对ASCII一样。 为了进行子字符串搜索等,您需要将其解码为某种用于表示Unicode字符的内部格式,然后对其进行子字符串搜索。由于远远超过Unicode 256个字符,因此字节(或字符)是不够的。这就是您找到的库使用整数的原因。 至于你的第二个问题,可能只是因为谈论负面字符没有意义,所以它们也可以被指定为“无符号”。     
我实施了一个
substr
&amp;
length
支持UTF8字符的功能。此代码是SQLite使用的修改版本。 以下宏循环输入文本并跳过所有多字节序列字符。
if
条件检查这是一个多字节序列,并且它内部的循环递增
input
直到找到下一个头字节。
#define SKIP_MULTI_BYTE_SEQUENCE(input) {              
    if( (*(input++)) >= 0xc0 ) {                        
    while( (*input & 0xc0) == 0x80 ){ input++; }       
  }                                                    
}
使用此宏实现
substr
length
typedef unsigned char utf8;
SUBSTR
void *substr(const utf8 *string, 
             int start, 
             int len, 
             utf8 **substring)
{
    int bytes, i;
    const utf8 *str2;
    utf8 *output;

    --start;
    while( *string && start ) {
        SKIP_MULTI_BYTE_SEQUENCE(string);
        --start;
    }

    for(str2 = string; *str2 && len; len--) {
        SKIP_MULTI_BYTE_SEQUENCE(str2);
    }

    bytes = (int) (str2 - string);
    output = *substring;
    for(i = 0; i < bytes; i++) {
        *output++ = *string++;
    }
    *output = '';
}
长度
int length(const utf8 *string)
{
    int len;
    len = 0;
    while( *string ) {
        ++len;
        SKIP_MULTI_BYTE_SEQUENCE(string);
    }
    return len;
}
    

要回复问题请先登录注册