我们系统的逻辑处理都是限制字节acsii的个数,正常不能限制字符个数,因为字符编码是变长的.这样在用strncpy时就可能cut off一个字符的中间字节,因此显示时会产生乱码.
有两种方法可以解决这个问题:
第一种方法是在strncpy前处理判断string的最后一个字符是否是合法的unicode.然后再得到copy的length
第二种方法:在strncpy后再判断产生的string,如果末尾字符是非法的unicode码,就去除它.
如何处理:1, 得到string’s 末尾指针
2, 取出最后一个字符的unicode码.
g_utf8_prev_char
g_utf8_get_char
3, 判断这个字符是否是非法的unicode码
g_unichar_validate
因为个人觉得方法2的performance比较高,而且对当前代码修改不大,如果有需要时才要加这个函数.所以下面是方法2的一个具体实现与测试代码
例子: #include <stdio.h>
#include <glib.h>
#include <stdlib.h>
#include <stdlib.h>
void alp_strip_trailing_invalid_character(gchar *srcP)
{
gunichar c = 0;
gint asciiLen = 0;
const gchar *srcEndOrigP = NULL;
gchar *srcEndP_acsii = NULL;
if (srcP == NULL) return;
asciiLen = strlen(srcP);
srcEndP_acsii = srcP + asciiLen;
srcEndOrigP = srcEndP_acsii;
while ( srcEndP_acsii > srcP ) {
srcEndP_acsii = g_utf8_prev_char(srcEndP_acsii);
c = g_utf8_get_char(srcEndP_acsii);
if (g_unichar_validate(c)) {
break;
}
}
if (srcEndOrigP > srcEndP_acsii) {
srcEndP_acsii = g_utf8_next_char(srcEndP_acsii);
if (g_utf8_pointer_to_offset(srcEndP_acsii, srcEndOrigP) >= 0 ){
memset(srcEndP_acsii, 0, g_utf8_pointer_to_offset(srcEndP_acsii, srcEndOrigP));
}
}
}
int main()
{
gchar *srcP = "f你我汉中fffe";
gchar descP[128]= {0};
gunichar c = 0;
gint len = 0;
const gchar *srcEndOrigP = NULL;
gchar *srcEndP = NULL;
if (srcP == NULL) return;
strncpy(descP, srcP, 4);
printf(" old descP=%s, strlen(descP)=%d/n",descP,strlen(descP));
alp_strip_trailing_invalid_character(descP);
printf("descP=%s/n",descP);
return 1;
}
gcc -o tripinvalid -finput-charset=GB2312 `pkg-config --cflags --libs glib-2.0` test_example.c
API的使用:
1, 传入参数要是数组
2, 正常用在strncpy可能产出的乱码,也可以用过输入性乱码.
3, 正常用于utf8编码的字符串,如果不是utf8可以强制转换一下.
Note:
1, gchar descP[128]= {0};
数组要初始化,用memset也行
2, 编码要指明charset,否则没法显示