我很难相信我是第一个遇到这个问题的人,但是我找了很长一段时间,却没有找到解决这个问题的办法。
我想使用strncpy,但是让它是UTF8感知的,这样它就不会部分地将utf8字符写入目标字符串。
否则,即使您知道源字符串是有效的(当源字符串大于最大长度时),也永远无法确保得到的字符串是有效的UTF8。
验证结果字符串可以工作,但是如果要调用它,最好有一个strncpy函数来检查它。
glib有g_utf8_strncpy,但是它复制了一定数量的unicode字符,而我在寻找一个限制字节长度的复制函数。
要明确的是,通过"utf8感知“,我的意思是它不应该超过目标缓冲区的限制,而且它必须从不只复制utf-8字符的一部分。(给定有效的utf-8输入,绝不能导致无效的utf-8输出)。
注意:
一些答复指出,strlcpy,会使所有字节为空,并且不会确保零终止,回想起来,我应该请求一个知道strncpy的utf8,但是,当时我还不知道这个函数的存在。
发布于 2011-09-15 13:58:07
为了回答自己的问题,下面是我最后得到的C函数(这个项目不使用C++ ):
注意:-意识到这不是strncpy for utf8的克隆,它更像openbsd的strlcpy。- utf8_skip_data是从glib的gutf8.c复制而来的--它不验证utf8 --这正是我的意图。
希望这对其他人有用,并对反馈感兴趣,但请不要对NULL终止行为发牢骚,除非它是一个实际的错误,或误导性/不正确的行为。
感谢James,他提供了这方面的基础,但不完整和C++ (我需要一个C版本)。
static const size_t utf8_skip_data[256] = {
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,
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,
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,
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,
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,
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,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,
3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,4,4,4,4,4,4,4,4,5,5,5,5,6,6,1,1
};
char *strlcpy_utf8(char *dst, const char *src, size_t maxncpy)
{
char *dst_r = dst;
size_t utf8_size;
if (maxncpy > 0) {
while (*src != '\0' && (utf8_size = utf8_skip_data[*((unsigned char *)src)]) < maxncpy) {
maxncpy -= utf8_size;
switch (utf8_size) {
case 6: *dst ++ = *src ++;
case 5: *dst ++ = *src ++;
case 4: *dst ++ = *src ++;
case 3: *dst ++ = *src ++;
case 2: *dst ++ = *src ++;
case 1: *dst ++ = *src ++;
}
}
*dst= '\0';
}
return dst_r;
}发布于 2015-01-08 04:05:57
我已经在许多带有多字节字符的示例UTF8字符串上测试了这一点。如果源太长,则对其进行反向搜索(从null终止符开始),并向后工作以找到最后一个适合于目标缓冲区的完整UTF8字符。它总是确保目标为null。
char* utf8cpy(char* dst, const char* src, size_t sizeDest )
{
if( sizeDest ){
size_t sizeSrc = strlen(src); // number of bytes not including null
while( sizeSrc >= sizeDest ){
const char* lastByte = src + sizeSrc; // Initially, pointing to the null terminator.
while( lastByte-- > src )
if((*lastByte & 0xC0) != 0x80) // Found the initial byte of the (potentially) multi-byte character (or found null).
break;
sizeSrc = lastByte - src;
}
memcpy(dst, src, sizeSrc);
dst[sizeSrc] = '\0';
}
return dst;
}发布于 2011-09-08 08:05:05
我不知道UTF-8是什么意思;strncpy复制字节,而不是字符,缓冲区的大小也是以字节为单位的。如果您的意思是它只复制完整的UTF-8字符,例如,如果没有下一个字符的空间,我不知道这样的函数,但是应该不会太难编写:
int
utf8Size( char ch )
{
static int const sizeTable[] =
{
// ...
};
return sizeTable( static_cast<unsigned char>( ch ) )
}
char*
stru8ncpy( char* dest, char* source, int n )
{
while ( *source != '\0' && utf8Size( *source ) < n ) {
n -= utf8Size( *source );
switch ( utf8Size( ch ) ) {
case 6:
*dest ++ = *source ++;
case 5:
*dest ++ = *source ++;
case 4:
*dest ++ = *source ++;
case 3:
*dest ++ = *source ++;
case 2:
*dest ++ = *source ++;
case 1:
*dest ++ = *source ++;
break;
default:
throw IllegalUTF8();
}
}
*dest = '\0';
return dest;
}(在utf8Size中生成表的内容有点痛苦,但是如果您处理UTF-8,并且只需要做一次,那么这是一个需要大量使用的函数。)
https://stackoverflow.com/questions/7344683
复制相似问题