jsj*_*jsj 56 c string unicode ascii
让我们说我有一个字符串:
char theString[] = "????a";
Run Code Online (Sandbox Code Playgroud)
鉴于我的编码是utf-8,这个字符串是12个字节长(三个hanzi字符各占三个字节,带有macron的拉丁字符是两个字节,'a'是一个字节:
strlen(theString) == 12
Run Code Online (Sandbox Code Playgroud)
我如何计算字符数?我该如何做相当于下标的内容,以便:
theString[3] == "?"
Run Code Online (Sandbox Code Playgroud)
我怎样才能切片,并捕捉这样的字符串?
pax*_*blo 29
您只计算前两位未设置的字符10
(即,所有字符都小于0x80
或大于0xbf
).
那是因为前两位设置的所有字符10
都是UTF-8连续字节.
有关编码的说明以及如何处理UTF-8字符串,请参见此处strlen
.
对于切片和切割UTF-8字符串,您基本上必须遵循相同的规则.任何以0
位或11
序列开头的字节都是UTF-8代码点的开头,所有其他字节都是连续字符.
如果您不想使用第三方库,最好的办法是简单地提供以下功能:
utf8left (char *destbuff, char *srcbuff, size_t sz);
utf8mid (char *destbuff, char *srcbuff, size_t pos, size_t sz);
utf8rest (char *destbuff, char *srcbuff, size_t pos;
Run Code Online (Sandbox Code Playgroud)
得到,分别:
sz
字符串的左UTF-8字节.sz
字符串的UTF-8字节,从pos
.pos
.这将是一个不错的构建块,能够为您的目的充分操纵字符串.
Mat*_*ner 15
试试这个尺码:
#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
// returns the number of utf8 code points in the buffer at s
size_t utf8len(char *s)
{
size_t len = 0;
for (; *s; ++s) if ((*s & 0xC0) != 0x80) ++len;
return len;
}
// returns a pointer to the beginning of the pos'th utf8 codepoint
// in the buffer at s
char *utf8index(char *s, size_t pos)
{
++pos;
for (; *s; ++s) {
if ((*s & 0xC0) != 0x80) --pos;
if (pos == 0) return s;
}
return NULL;
}
// converts codepoint indexes start and end to byte offsets in the buffer at s
void utf8slice(char *s, ssize_t *start, ssize_t *end)
{
char *p = utf8index(s, *start);
*start = p ? p - s : -1;
p = utf8index(s, *end);
*end = p ? p - s : -1;
}
// appends the utf8 string at src to dest
char *utf8cat(char *dest, char *src)
{
return strcat(dest, src);
}
// test program
int main(int argc, char **argv)
{
// slurp all of stdin to p, with length len
char *p = malloc(0);
size_t len = 0;
while (true) {
p = realloc(p, len + 0x10000);
ssize_t cnt = read(STDIN_FILENO, p + len, 0x10000);
if (cnt == -1) {
perror("read");
abort();
} else if (cnt == 0) {
break;
} else {
len += cnt;
}
}
// do some demo operations
printf("utf8len=%zu\n", utf8len(p));
ssize_t start = 2, end = 3;
utf8slice(p, &start, &end);
printf("utf8slice[2:3]=%.*s\n", end - start, p + start);
start = 3; end = 4;
utf8slice(p, &start, &end);
printf("utf8slice[3:4]=%.*s\n", end - start, p + start);
return 0;
}
Run Code Online (Sandbox Code Playgroud)
样品运行:
matt@stanley:~/Desktop$ echo -n ????a | ./utf8ops
utf8len=5
utf8slice[2:3]=?
utf8slice[3:4]=?
Run Code Online (Sandbox Code Playgroud)
请注意,您的示例有一个错误. theString[2] == "?"
根据您对"角色"的概念,这个问题可能会或多或少地受到影响.
首先,您应该将字节字符串转换为一串unicode代码点.您可以使用iconv()
ICU 执行此操作,但如果这是您唯一的操作,iconv()
则更容易,并且它是POSIX的一部分.
您的unicode代码点字符串可能类似于以null结尾uint32_t[]
,或者如果您有C1x,则是一个数组char32_t
.该数组的大小(即它的元素数,而不是它的大小,以字节为单位)是代码点的数量(加上终结符),这应该会给你一个很好的开始.
但是,"可打印字符"的概念相当复杂,您可能更喜欢计算字形而不是代码点 - 例如,a
带有重音的^
可以表示为两个unicode代码点,或者表示为组合的遗留代码点â
- 两者都有效,并且unicode标准要求两者同等对待.有一个称为"规范化"的过程会将你的字符串变成一个确定的版本,但是有许多字形表示不能作为单个代码点表达,并且通常没有办法解决这个问题,并为你计算字形数据. .
也就是说,由您来决定脚本的复杂程度以及您希望如何彻底对待它们.转换为unicode代码点是必须的,除此之外的一切都由您自行决定.
如果您决定需要ICU,请随时提出有关ICU的问题,但请先随意探索更简单的问题iconv()
.
归档时间: |
|
查看次数: |
17139 次 |
最近记录: |