是否真的可以在 C 上存储和处理单个 UTF-8 字符?如果是这样,如何?
Is it actually possible to store and process individual UTF-8 characters on C ? If so, how?
我用 C 编写了一个程序,可以将单词分解为音节、句段和字母。它适用于 ASCII 字符,但我也想制作适用于 IPA 和阿拉伯语的版本。
我在保存和执行个别角色的功能时遇到了很多问题。我的编辑器和控制台都设置为 UTF-8,如果我将其保存为 char*,则可以很好地显示阿拉伯文本,但是当我尝试打印 wchars 时,它们会显示随机标点符号。
我的程序需要能够识别单个 UTF-8 字符才能工作。例如,对于单词'though',它将't'存储为音节[1]段[1]字母[1],h存储为音节[1]段[1]字母[2]等。我想要能够对非 ASCII 字符执行相同的操作。
我基本上花了一整天时间研究 unicode 并尝试不同的方法,但我无法让任何方法让我将阿拉伯字符存储为字符。
我不确定我是不是犯了一些愚蠢的语法错误,我是否完全误解了整个概念,或者我是否真的无法在 C 中做我想做的事我应该放弃并尝试另一种语言...
我将非常、非常、非常感谢您提供的任何帮助!我对编程还很陌生,但 unicode 对我的工作完全有帮助,所以我想从一开始就弄清楚如何去做。
我对 unicode 工作原理的理解(以防那是我出错的地方):
我在编辑器中输入了一些文本。我的编辑器根据我设置的编码对其进行编码。因此,如果我将它设置为 UFT-8,它将使用 2 字节序列 0xd8 0xab 对阿拉伯字母 Ø 进行编码,这表示代码点 U+0628.
我编译了,把0xd8 0xab分解成二进制11011000 10101000.
我运行它在命令提示符下。命令提示符根据我设置的编码解释文本,所以如果我将它设置为 UFT-8,它应该将 11011000 10101000 解释为代码点 U+0628。 Unicode 算法还告诉它向我显示哪个版本的 U+0628,因为字符根据其在单词中的位置具有不同的形状。由于这个角色是一个人,所以它会显示独立版本 Ø
我对C中unicode处理方式的理解:
选项 A - 使用编码为 UTF-8 的单字节 (http://www.nubaria.com/en/blog/?p=289)
使用编码为 UTF-8 的单字节。将我所有的数据类型保留为 chars 和 char 数组,并在我的代码中只键入 ASCII 字符。如果我绝对必须对 unicode 字符进行硬编码,请按以下格式将其作为数组输入:
const char kChineseSampleText[] = "\xe4\xb8\xad\xe6\x96\x87";
我的问题:
- 我需要操作单个字符
- 必须键入阿拉伯字符作为代码点将使我的代码完全不可读,并极大地拖慢我的速度。
选项 B - 使用 wchar 和朋友 (http://icu-project.org/docs/papers/unicode_wchar_t.html)
使用 chars 交换 wchars,根据编译器的不同,wchars 可以容纳 2 到 4 个字节。像 strlen 这样的字符串函数将不起作用,因为它们期望字符是一个字节,但是我可以使用像 wprintf 这样的 w 函数。
我的问题是:
我根本无法让 wchars 打印阿拉伯字符!我可以让他们很好地打印英文字母,但阿拉伯字符只是作为随机标点符号出现。
我已经尝试输入 unicode 代码点以及实际的阿拉伯字符,我已经尝试将它们打印到控制台和 UTF-8 编码的文本文件,我得到了相同的结果,即使如果以 char* 形式输入,控制台和文本文件都会显示阿拉伯文本。我在最后包含了我的代码。
(在这里值得一提的是,我知道很多人认为 wchars 不好,因为它们不是很便携,因为它们占用了额外的 space 作为 ASCII 字符。但在这个阶段,这些事情对我来说都不是真正的担心 - 我只是在我自己的计算机上将程序编写到 运行 并且程序只会处理短字符串。)
选项 C - 使用外部库
我在各种评论中读到外部库是可行的方法,所以我尝试了:
C编程库
http://www.cprogramming.com/tutorial/unicode.html 建议用无符号长整数替换所有字符,并使用特殊函数遍历字符串等。该站点甚至提供了一个示例库供下载。
我的问题:
虽然我可以将字符设置为无符号长整数,但我无法将其打印出来,因为 printf 和 wprintf 函数不起作用,网站上提供的库也不起作用(我想也许是库是为 Linux 设计的?一些数据类型无效,修改它们也不起作用)
ICU图书馆
我的问题:
我下载了 ICU 库,但是当我研究如何使用它时,我发现诸如 characterIterator 之类的功能在 C 中不可用 (http://userguide.icu-project.org/strings)。能够遍历字符对于我需要做的事情来说是完全基础的,所以我认为这个库不适合我。
我的代码
#include <stdio.h>
#include <stdlib.h>
#include <wchar.h>
#include <locale.h>
#include <string.h>
int main ()
{
wchar_t unicode = L'\xd8ac';
wchar_t arabic = L'ب';
wchar_t number = 0x062c;
FILE* f;
f = fopen("unitest.txt","w");
char* string = "ايه الاخبار";
//printf - works
printf("printf - literal arabic character is \"م\"\n");
fprintf(f,"printf - literal arabic character is \"م\"\n");
printf("printf - char* string is \"%s\"\n",string);
fprintf(f,"printf - char* string is \"%s\"\n",string);
//wprintf - english - works
wprintf(L"wprintf - literal english char is \"%C\"\n\n", L't');
fwprintf(f,L"wprintf - literal english char is \"%C\"\n\n", L't');
//wprintf - arabic - doesnt work
wprintf(L"wprintf - unicode wchar_t is \"%C\"\n", unicode);
fwprintf(f,L"wprintf - unicode wchar_t is \"%C\"\n", unicode);
wprintf(L"wprintf - unicode number wchar_t is \"%C\"\n", number);
fwprintf(f,L"wprintf - unicode number wchar_t is \"%C\"\n", number);
wprintf(L"wprintf - arabic wchar_t is \"%C\"\n", arabic);
fwprintf(f,L"wprintf - arabic wchar_t is \"%C\"\n", arabic);
wprintf(L"wprintf - literal arabic character is \"%C\"\n",L'ت');
fwprintf(f,L"wprintf - literal arabic character is \"%C\"\n",L'ت');
wprintf(L"wprintf - literal arabic character in string is \"م\"\n\n");
fwprintf(f,L"wprintf - literal arabic character in string is \"م\"\n\n");
fclose(f);
return 0;
}
输出文件
printf - literal arabic character is "م"
printf - char* string is "ايه الاخبار"
wprintf - literal english char is "t"
wprintf - unicode wchar_t is "�"
wprintf - unicode number wchar_t is ","
wprintf - arabic wchar_t is "("
wprintf - literal arabic character is "*"
wprintf - literal arabic character in string is ""
我正在使用 Windows 10、Notepad++ 和 MinGW。
编辑
这被标记为 Light C Unicode Library 的副本,但我认为它并不能真正回答我的问题。我已经下载了库并看了一下,如果你愿意,你可以说我笨,但我真的是编程新手,我不理解库中的大部分代码,所以我很难工作了解如何使用它来实现我想要的。我在图书馆中搜索了打印功能,但找不到...
我只想保存一个UTF-8字符,然后再打印出来!我真的需要安装整个库才能做到这一点吗?我真的很感激有人同情我并用婴儿的方式告诉我我该怎么做...人们一直说我应该使用 uint_32 或其他东西而不是 wchar - 但我该如何 print那些数据类型?我可以用 wprintf 做吗?!
C 和 UTF-8 仍在相互了解。换句话说,IMO, C support for UTF-8 不足。
Is it ... possible to store and process individual UTF-8 characters ...?
第一步是确定 "ايه الاخبار"
是 UTF-8 编码的字符串。 C 明确支持 u8"ايه الاخبار"
.
UTF-8 string
是 char
的序列。每个 1 到 4 char
代表一个 Unicode 字符。 Unicode 字符至少需要 21 位进行编码。然而,OP 不需要将 string[]
的一部分转换为 Unicode 字符,就像想要在 UTF-8 边界上对该字符串进行分段一样。这很容易通过查找 UTF-8 continuation bytes.
找到
以下构成编码为 UTF-8 字符串的 1 Unicode 字符,并带有终止 空字符 。然后打印那个短字符串。
char* string = u8"ايه الاخبار";
for (char *s = string; *s; ) {
printf("<");
char u[5];
char *p = u;
*p++ = *s++;
if ((*s & 0xC0) == 0x80) *p++ = *s++;
if ((*s & 0xC0) == 0x80) *p++ = *s++;
if ((*s & 0xC0) == 0x80) *p++ = *s++;
*p = 0;
printf("%s", u);
printf(">\n");
}
使用支持 UTF8 的屏幕查看输出:
<ا>
<ي>
<ه>
< >
<ا>
<ل>
<ا>
<خ>
<ب>
<ا>
<ر>
您需要非常清楚地了解 Unicode 代码点和 UTF-8 之间的区别。 UTF-8 是 Unicode 代码点的可变字节编码。低端值 0-127 存储为单个字节。这是 UTF-8 的要点,并使其向后兼容 Ascii。
设置位 7 时,对于超过 127 的值,使用两个字节或更多字节的可变长度代码。前导字节始终具有位模式 11xxxxxx。
这是获取跳过(使用的字符数)、读取代码点和写入代码点的代码。
static const unsigned int offsetsFromUTF8[6] =
{
0x00000000UL, 0x00003080UL, 0x000E2080UL,
0x03C82080UL, 0xFA082080UL, 0x82082080UL
};
static const unsigned char trailingBytesForUTF8[256] = {
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, 3,3,3,3,3,3,3,3,4,4,4,4,5,5,5,5
};
int bbx_utf8_skip(const char *utf8)
{
return trailingBytesForUTF8[(unsigned char) *utf8] + 1;
}
int bbx_utf8_getch(const char *utf8)
{
int ch;
int nb;
nb = trailingBytesForUTF8[(unsigned char)*utf8];
ch = 0;
switch (nb)
{
/* these fall through deliberately */
case 3: ch += (unsigned char)*utf8++; ch <<= 6;
case 2: ch += (unsigned char)*utf8++; ch <<= 6;
case 1: ch += (unsigned char)*utf8++; ch <<= 6;
case 0: ch += (unsigned char)*utf8++;
}
ch -= offsetsFromUTF8[nb];
return ch;
}
int bbx_utf8_putch(char *out, int ch)
{
char *dest = out;
if (ch < 0x80)
{
*dest++ = (char)ch;
}
else if (ch < 0x800)
{
*dest++ = (ch>>6) | 0xC0;
*dest++ = (ch & 0x3F) | 0x80;
}
else if (ch < 0x10000)
{
*dest++ = (ch>>12) | 0xE0;
*dest++ = ((ch>>6) & 0x3F) | 0x80;
*dest++ = (ch & 0x3F) | 0x80;
}
else if (ch < 0x110000)
{
*dest++ = (ch>>18) | 0xF0;
*dest++ = ((ch>>12) & 0x3F) | 0x80;
*dest++ = ((ch>>6) & 0x3F) | 0x80;
*dest++ = (ch & 0x3F) | 0x80;
}
else
return 0;
return dest - out;
}
使用这些函数或类似函数,您可以在代码点和 UTF-8 之间进行转换
然后回来。
Windows 目前使用 UTF-16 作为其 api。大致来说,UTF-16 是 16 位格式的代码点。因此,在编写基于 UTF-8 的程序时,您需要在调用 Windows 输出函数之前立即将 UTF-8 转换为 UTF-16(使用宽字符)。
通过 printf() 对 UTF-8 的支持是不完整的。将 UTF-8 编码的字符串传递给 printf() 不太可能执行您想要的操作。
要迭代的 utf8proc 库示例是:
#include <utf8proc.h>
#include <stdio.h>
int main(void) {
utf8proc_uint8_t const string[] = u8"ايه الاخبار";
utf8proc_ssize_t size = sizeof string / sizeof *string - 1;
utf8proc_int32_t data;
utf8proc_ssize_t n;
utf8proc_uint8_t const *pstring = string;
while ((n = utf8proc_iterate(pstring, size, &data)) > 0) {
printf("<%.*s>\n", (int)n, pstring);
pstring += n;
size -= n;
}
}
这可能不是使用此库的最佳方式,但我制作了一个 issue 和 github 来提供一些示例。因为,我无法理解这个库是如何工作的。
我用 C 编写了一个程序,可以将单词分解为音节、句段和字母。它适用于 ASCII 字符,但我也想制作适用于 IPA 和阿拉伯语的版本。
我在保存和执行个别角色的功能时遇到了很多问题。我的编辑器和控制台都设置为 UTF-8,如果我将其保存为 char*,则可以很好地显示阿拉伯文本,但是当我尝试打印 wchars 时,它们会显示随机标点符号。
我的程序需要能够识别单个 UTF-8 字符才能工作。例如,对于单词'though',它将't'存储为音节[1]段[1]字母[1],h存储为音节[1]段[1]字母[2]等。我想要能够对非 ASCII 字符执行相同的操作。
我基本上花了一整天时间研究 unicode 并尝试不同的方法,但我无法让任何方法让我将阿拉伯字符存储为字符。
我不确定我是不是犯了一些愚蠢的语法错误,我是否完全误解了整个概念,或者我是否真的无法在 C 中做我想做的事我应该放弃并尝试另一种语言...
我将非常、非常、非常感谢您提供的任何帮助!我对编程还很陌生,但 unicode 对我的工作完全有帮助,所以我想从一开始就弄清楚如何去做。
我对 unicode 工作原理的理解(以防那是我出错的地方):
我在编辑器中输入了一些文本。我的编辑器根据我设置的编码对其进行编码。因此,如果我将它设置为 UFT-8,它将使用 2 字节序列 0xd8 0xab 对阿拉伯字母 Ø 进行编码,这表示代码点 U+0628.
我编译了,把0xd8 0xab分解成二进制11011000 10101000.
我运行它在命令提示符下。命令提示符根据我设置的编码解释文本,所以如果我将它设置为 UFT-8,它应该将 11011000 10101000 解释为代码点 U+0628。 Unicode 算法还告诉它向我显示哪个版本的 U+0628,因为字符根据其在单词中的位置具有不同的形状。由于这个角色是一个人,所以它会显示独立版本 Ø
我对C中unicode处理方式的理解:
选项 A - 使用编码为 UTF-8 的单字节 (http://www.nubaria.com/en/blog/?p=289)
使用编码为 UTF-8 的单字节。将我所有的数据类型保留为 chars 和 char 数组,并在我的代码中只键入 ASCII 字符。如果我绝对必须对 unicode 字符进行硬编码,请按以下格式将其作为数组输入:
const char kChineseSampleText[] = "\xe4\xb8\xad\xe6\x96\x87";
我的问题:
- 我需要操作单个字符
- 必须键入阿拉伯字符作为代码点将使我的代码完全不可读,并极大地拖慢我的速度。
选项 B - 使用 wchar 和朋友 (http://icu-project.org/docs/papers/unicode_wchar_t.html)
使用 chars 交换 wchars,根据编译器的不同,wchars 可以容纳 2 到 4 个字节。像 strlen 这样的字符串函数将不起作用,因为它们期望字符是一个字节,但是我可以使用像 wprintf 这样的 w 函数。
我的问题是:
我根本无法让 wchars 打印阿拉伯字符!我可以让他们很好地打印英文字母,但阿拉伯字符只是作为随机标点符号出现。
我已经尝试输入 unicode 代码点以及实际的阿拉伯字符,我已经尝试将它们打印到控制台和 UTF-8 编码的文本文件,我得到了相同的结果,即使如果以 char* 形式输入,控制台和文本文件都会显示阿拉伯文本。我在最后包含了我的代码。
(在这里值得一提的是,我知道很多人认为 wchars 不好,因为它们不是很便携,因为它们占用了额外的 space 作为 ASCII 字符。但在这个阶段,这些事情对我来说都不是真正的担心 - 我只是在我自己的计算机上将程序编写到 运行 并且程序只会处理短字符串。)
选项 C - 使用外部库
我在各种评论中读到外部库是可行的方法,所以我尝试了:
C编程库
http://www.cprogramming.com/tutorial/unicode.html 建议用无符号长整数替换所有字符,并使用特殊函数遍历字符串等。该站点甚至提供了一个示例库供下载。
我的问题:
虽然我可以将字符设置为无符号长整数,但我无法将其打印出来,因为 printf 和 wprintf 函数不起作用,网站上提供的库也不起作用(我想也许是库是为 Linux 设计的?一些数据类型无效,修改它们也不起作用)
ICU图书馆
我的问题:
我下载了 ICU 库,但是当我研究如何使用它时,我发现诸如 characterIterator 之类的功能在 C 中不可用 (http://userguide.icu-project.org/strings)。能够遍历字符对于我需要做的事情来说是完全基础的,所以我认为这个库不适合我。
我的代码
#include <stdio.h>
#include <stdlib.h>
#include <wchar.h>
#include <locale.h>
#include <string.h>
int main ()
{
wchar_t unicode = L'\xd8ac';
wchar_t arabic = L'ب';
wchar_t number = 0x062c;
FILE* f;
f = fopen("unitest.txt","w");
char* string = "ايه الاخبار";
//printf - works
printf("printf - literal arabic character is \"م\"\n");
fprintf(f,"printf - literal arabic character is \"م\"\n");
printf("printf - char* string is \"%s\"\n",string);
fprintf(f,"printf - char* string is \"%s\"\n",string);
//wprintf - english - works
wprintf(L"wprintf - literal english char is \"%C\"\n\n", L't');
fwprintf(f,L"wprintf - literal english char is \"%C\"\n\n", L't');
//wprintf - arabic - doesnt work
wprintf(L"wprintf - unicode wchar_t is \"%C\"\n", unicode);
fwprintf(f,L"wprintf - unicode wchar_t is \"%C\"\n", unicode);
wprintf(L"wprintf - unicode number wchar_t is \"%C\"\n", number);
fwprintf(f,L"wprintf - unicode number wchar_t is \"%C\"\n", number);
wprintf(L"wprintf - arabic wchar_t is \"%C\"\n", arabic);
fwprintf(f,L"wprintf - arabic wchar_t is \"%C\"\n", arabic);
wprintf(L"wprintf - literal arabic character is \"%C\"\n",L'ت');
fwprintf(f,L"wprintf - literal arabic character is \"%C\"\n",L'ت');
wprintf(L"wprintf - literal arabic character in string is \"م\"\n\n");
fwprintf(f,L"wprintf - literal arabic character in string is \"م\"\n\n");
fclose(f);
return 0;
}
输出文件
printf - literal arabic character is "م"
printf - char* string is "ايه الاخبار"
wprintf - literal english char is "t"
wprintf - unicode wchar_t is "�"
wprintf - unicode number wchar_t is ","
wprintf - arabic wchar_t is "("
wprintf - literal arabic character is "*"
wprintf - literal arabic character in string is ""
我正在使用 Windows 10、Notepad++ 和 MinGW。
编辑 这被标记为 Light C Unicode Library 的副本,但我认为它并不能真正回答我的问题。我已经下载了库并看了一下,如果你愿意,你可以说我笨,但我真的是编程新手,我不理解库中的大部分代码,所以我很难工作了解如何使用它来实现我想要的。我在图书馆中搜索了打印功能,但找不到...
我只想保存一个UTF-8字符,然后再打印出来!我真的需要安装整个库才能做到这一点吗?我真的很感激有人同情我并用婴儿的方式告诉我我该怎么做...人们一直说我应该使用 uint_32 或其他东西而不是 wchar - 但我该如何 print那些数据类型?我可以用 wprintf 做吗?!
C 和 UTF-8 仍在相互了解。换句话说,IMO, C support for UTF-8 不足。
Is it ... possible to store and process individual UTF-8 characters ...?
第一步是确定 "ايه الاخبار"
是 UTF-8 编码的字符串。 C 明确支持 u8"ايه الاخبار"
.
UTF-8 string
是 char
的序列。每个 1 到 4 char
代表一个 Unicode 字符。 Unicode 字符至少需要 21 位进行编码。然而,OP 不需要将 string[]
的一部分转换为 Unicode 字符,就像想要在 UTF-8 边界上对该字符串进行分段一样。这很容易通过查找 UTF-8 continuation bytes.
以下构成编码为 UTF-8 字符串的 1 Unicode 字符,并带有终止 空字符 。然后打印那个短字符串。
char* string = u8"ايه الاخبار";
for (char *s = string; *s; ) {
printf("<");
char u[5];
char *p = u;
*p++ = *s++;
if ((*s & 0xC0) == 0x80) *p++ = *s++;
if ((*s & 0xC0) == 0x80) *p++ = *s++;
if ((*s & 0xC0) == 0x80) *p++ = *s++;
*p = 0;
printf("%s", u);
printf(">\n");
}
使用支持 UTF8 的屏幕查看输出:
<ا>
<ي>
<ه>
< >
<ا>
<ل>
<ا>
<خ>
<ب>
<ا>
<ر>
您需要非常清楚地了解 Unicode 代码点和 UTF-8 之间的区别。 UTF-8 是 Unicode 代码点的可变字节编码。低端值 0-127 存储为单个字节。这是 UTF-8 的要点,并使其向后兼容 Ascii。
设置位 7 时,对于超过 127 的值,使用两个字节或更多字节的可变长度代码。前导字节始终具有位模式 11xxxxxx。
这是获取跳过(使用的字符数)、读取代码点和写入代码点的代码。
static const unsigned int offsetsFromUTF8[6] =
{
0x00000000UL, 0x00003080UL, 0x000E2080UL,
0x03C82080UL, 0xFA082080UL, 0x82082080UL
};
static const unsigned char trailingBytesForUTF8[256] = {
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, 3,3,3,3,3,3,3,3,4,4,4,4,5,5,5,5
};
int bbx_utf8_skip(const char *utf8)
{
return trailingBytesForUTF8[(unsigned char) *utf8] + 1;
}
int bbx_utf8_getch(const char *utf8)
{
int ch;
int nb;
nb = trailingBytesForUTF8[(unsigned char)*utf8];
ch = 0;
switch (nb)
{
/* these fall through deliberately */
case 3: ch += (unsigned char)*utf8++; ch <<= 6;
case 2: ch += (unsigned char)*utf8++; ch <<= 6;
case 1: ch += (unsigned char)*utf8++; ch <<= 6;
case 0: ch += (unsigned char)*utf8++;
}
ch -= offsetsFromUTF8[nb];
return ch;
}
int bbx_utf8_putch(char *out, int ch)
{
char *dest = out;
if (ch < 0x80)
{
*dest++ = (char)ch;
}
else if (ch < 0x800)
{
*dest++ = (ch>>6) | 0xC0;
*dest++ = (ch & 0x3F) | 0x80;
}
else if (ch < 0x10000)
{
*dest++ = (ch>>12) | 0xE0;
*dest++ = ((ch>>6) & 0x3F) | 0x80;
*dest++ = (ch & 0x3F) | 0x80;
}
else if (ch < 0x110000)
{
*dest++ = (ch>>18) | 0xF0;
*dest++ = ((ch>>12) & 0x3F) | 0x80;
*dest++ = ((ch>>6) & 0x3F) | 0x80;
*dest++ = (ch & 0x3F) | 0x80;
}
else
return 0;
return dest - out;
}
使用这些函数或类似函数,您可以在代码点和 UTF-8 之间进行转换 然后回来。
Windows 目前使用 UTF-16 作为其 api。大致来说,UTF-16 是 16 位格式的代码点。因此,在编写基于 UTF-8 的程序时,您需要在调用 Windows 输出函数之前立即将 UTF-8 转换为 UTF-16(使用宽字符)。
通过 printf() 对 UTF-8 的支持是不完整的。将 UTF-8 编码的字符串传递给 printf() 不太可能执行您想要的操作。
要迭代的 utf8proc 库示例是:
#include <utf8proc.h>
#include <stdio.h>
int main(void) {
utf8proc_uint8_t const string[] = u8"ايه الاخبار";
utf8proc_ssize_t size = sizeof string / sizeof *string - 1;
utf8proc_int32_t data;
utf8proc_ssize_t n;
utf8proc_uint8_t const *pstring = string;
while ((n = utf8proc_iterate(pstring, size, &data)) > 0) {
printf("<%.*s>\n", (int)n, pstring);
pstring += n;
size -= n;
}
}
这可能不是使用此库的最佳方式,但我制作了一个 issue 和 github 来提供一些示例。因为,我无法理解这个库是如何工作的。