Max*_*kin 33
来自Unix/Linux的UTF-8和Unicode FAQ:
可以使用便携式方式在C中计算字符数
mbstowcs(NULL,s,0).只要选择了适当的语言环境,这适用于UTF-8,就像任何其他支持的编码一样.计算UTF-8字符串中字符数的硬连线技术是计算除0x80 - 0xBF范围内的所有字节,因为这些只是连续字节而不是它们自己的字符.然而,在应用程序中很少出现计算字符的需要.
mpe*_*ez0 21
您可能有也可能没有UTF-8兼容的strlen(3)功能.但是,有一些简单的C函数可以快速完成工作.
高效的C解决方案检查字符的开头是否跳过连续字节.简单的代码(从上面的链接引用)是
int my_strlen_utf8_c(char *s) {
int i = 0, j = 0;
while (s[i]) {
if ((s[i] & 0xc0) != 0x80) j++;
i++;
}
return j;
}
Run Code Online (Sandbox Code Playgroud)
较快的版本使用相同的技术,但预取数据并进行多字节比较,从而产生了大量的加速.但是,代码更长,更复杂.
我很震惊,没有人提到这一点,所以这里有记录:
如果要在终端中对齐文本,则需要使用POSIX函数wcwidth和wcswidth.这是找到字符串的屏幕长度的正确程序.
#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]));
}
}
Run Code Online (Sandbox Code Playgroud)
以下是它运行的示例:
$ ./measure hello ?? c?b
hello: 5
??: 4
c?b: 4
Run Code Online (Sandbox Code Playgroud)
注意两个字符"庄子"和三个字符"cAb"(注意双宽度A)都是4列宽.
正如utf8everywhere.org 所说,
屏幕上显示的字符串大小与字符串中的代码点数无关.为此,必须与渲染引擎进行通信.即使在等宽字体和终端中,代码点也不占用一列.POSIX考虑到了这一点.
Windows没有任何内置的wcwidth控制台输出功能; 如果你想在Windows控制台中支持多列字符,你需要找到一个可放弃wcwidth的可移植实现,因为Windows控制台不支持Unicode而没有疯狂的黑客攻击.
| 归档时间: |
|
| 查看次数: |
26398 次 |
| 最近记录: |