#define _XOPEN_SOURCE
#include <wchar.h>
#include <stdio.h>
#include <locale.h>
#include <stdlib.h>
int measure(char *string) {
// allocate enough memory to hold the wide string
size_t needed = mbstowcs(NULL, string, 0) + 1;
wchar_t *wcstring = malloc(needed * sizeof *wcstring);
if (!wcstring) return -1;
// change encodings
if (mbstowcs(wcstring, string, needed) == (size_t)-1) return -2;
// measure width
int width = wcswidth(wcstring, needed);
free(wcstring);
return width;
}
int main(int argc, char **argv) {
setlocale(LC_ALL, "");
for (int i = 1; i < argc; i++) {
printf("%s: %d\n", argv[i], measure(argv[i]));
}
}
下面是它运行的一个示例:
$ ./measure hello 莊子 cAb
hello: 5
莊子: 4
cAb: 4
Note how the two characters "莊子" and the three characters "cAb" (note the double-width A) are both 4 columns wide. 正如utf8everywhere.org所说, 字符串在屏幕上显示的大小与字符串中的代码点数无关。为此,必须与渲染引擎进行通信。即使在等宽字体和终端中,代码点数也不占用一列。POSIX考虑到了这一点。 Windows没有任何用于控制台输出的内置wcwidth函数;如果你想在Windows控制台中支持多列字符,你需要找到wcwidth的可移植实现给予,因为Windows控制台不支持Unicode,除非有疯狂的黑客攻击。
6条答案
按热度按时间7nbnzgx91#
来自Unix/Linux的UTF-8和Unicode常见问题解答:
在C语言中,可以使用
mbstowcs(NULL,s,0)
以可移植的方式计算字符数。只要选择了适当的语言环境,这对UTF-8和其他支持的编码一样有效。计算UTF-8字符串中字符数的硬连线技术是计算除0x 80 - 0xBF范围外的所有字节。因为这些只是连续字节而不是它们自己的字符。然而,在应用程序中,对字符计数的需求却出奇地少。11dmarpk2#
您可能有也可能没有UTF-8兼容的strlen(3)函数,但是有一些ome simple C functions readily available可以快速完成这项工作。
高效的C解决方案检查字符的开头以跳过连续字节。
更快的版本使用相同的技术,但是预取数据和进行多字节比较,结果是一个实质性的加速,但是代码更长更复杂。
9wbgstp73#
我很震惊没有人提到这一点,所以在这里记录:
如果你想在终端中对齐文本,你需要使用POSIX函数
wcwidth
和wcswidth
。下面是正确的程序来查找字符串在屏幕上的长度。下面是它运行的一个示例:
Note how the two characters "莊子" and the three characters "cAb" (note the double-width A) are both 4 columns wide.
正如utf8everywhere.org所说,
字符串在屏幕上显示的大小与字符串中的代码点数无关。为此,必须与渲染引擎进行通信。即使在等宽字体和终端中,代码点数也不占用一列。POSIX考虑到了这一点。
Windows没有任何用于控制台输出的内置
wcwidth
函数;如果你想在Windows控制台中支持多列字符,你需要找到wcwidth
的可移植实现给予,因为Windows控制台不支持Unicode,除非有疯狂的黑客攻击。cbeh67ev4#
如果您能够使用第三方库,请查看IBM的ICU library。
z5btuh9x5#
下面的代码考虑了格式错误的字节序列。字符串数据的示例来自Unicode标准6.3中的“"Table 3-8. Use of U+FFFD in UTF-8 Conversion"“。
当我为UTF-8编写代码时,我看到了Unicode标准6.3中的“表3-7.格式良好的UTF-8字节序列”。
wqnecbli6#
您还可以使用glib,这使您在处理UTF-8.glib reference docs时更加轻松