免费注册 查看新帖 |

Chinaunix

  平台 论坛 博客 文库
12下一页
最近访问板块 发新帖
查看: 11546 | 回复: 12

[算法] 一个高效过滤非UTF8字符的C函数 [复制链接]

论坛徽章:
4
2015年辞旧岁徽章
日期:2015-03-03 16:54:152015年迎新春徽章
日期:2015-03-04 09:56:11IT运维版块每日发帖之星
日期:2016-08-11 06:20:00IT运维版块每日发帖之星
日期:2016-08-15 06:20:00
发表于 2008-07-31 11:21 |显示全部楼层

  1. /*
  2. UTF-8 valid format list:
  3. 0xxxxxxx
  4. 110xxxxx 10xxxxxx
  5. 1110xxxx 10xxxxxx 10xxxxxx
  6. 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx
  7. 111110xx 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx
  8. 1111110x 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx
  9. */
  10. char *filter_none_utf8_chars(char *src, int *len)
  11. {
  12.         unsigned char *p;
  13.         unsigned char *pSub;
  14.         unsigned char *pStrEnd;
  15.         unsigned char *pCharEnd;
  16.         int bytes;
  17.         unsigned char *filtered;
  18.         unsigned char *pDest;
  19.         unsigned char *pInvalidCharStart;
  20.         pStrEnd = (unsigned char *)src + (*len);
  21.         p = (unsigned char *)src;
  22.         pInvalidCharStart = NULL;
  23.         while (p < pStrEnd)
  24.         {
  25.                 if (*p < 0x80)
  26.                 {
  27.                         p++;
  28.                         continue;
  29.                 }
  30.                 if ((*p & 0xE0) == 0xC0)  //110xxxxx
  31.                 {
  32.                         bytes = 1;
  33.                 }
  34.                 else if ((*p & 0xF0) == 0xE0) //1110xxxx
  35.                 {
  36.                         bytes = 2;
  37.                 }
  38.                 else if ((*p & 0xF8) == 0xF0) //11110xxx
  39.                 {
  40.                         bytes = 3;
  41.                 }
  42.                 else if ((*p & 0xFC) == 0xF8) //111110xx
  43.                 {
  44.                         bytes = 4;
  45.                 }
  46.                 else if ((*p & 0xFE) == 0xFC) //1111110x
  47.                 {
  48.                         bytes = 5;
  49.                 }
  50.                 else
  51.                 {
  52.                         pInvalidCharStart = p;
  53.                         break;
  54.                 }

  55.                 p++;
  56.                 pCharEnd = p + bytes;
  57.                 if (pCharEnd > pStrEnd)
  58.                 {
  59.                         pInvalidCharStart = p - 1;
  60.                         break;
  61.                 }
  62.                 for (; p<pCharEnd; p++)
  63.                 {
  64.                         if ((*p & 0xC0) != 0x80)
  65.                         {
  66.                                 break;
  67.                         }
  68.                 }
  69.                 if (p != pCharEnd)
  70.                 {
  71.                         pInvalidCharStart = pCharEnd - (bytes + 1);
  72.                         break;
  73.                 }
  74.         }
  75.         if (pInvalidCharStart == NULL) //all chars are valid
  76.         {
  77.                 return src;
  78.         }

  79.         filtered = (unsigned char *)malloc(sizeof(char) * (*len));
  80.         if (filtered == NULL)
  81.         {
  82.                 *len = 0;
  83.                 *src = '\0';
  84.                 return src;
  85.         }

  86.         pDest = filtered;
  87.         bytes = (char *)pInvalidCharStart - src;
  88.         if (bytes > 0)
  89.         {
  90.                 memcpy(pDest, src, bytes);
  91.                 pDest += bytes;
  92.         }

  93.         p = pInvalidCharStart + 1; //skip this invalid char
  94.         while (p < pStrEnd)
  95.         {
  96.                 if (*p < 0x80)
  97.                 {
  98.                         *pDest++ = *p++;
  99.                         continue;
  100.                 }
  101.                 if ((*p & 0xE0) == 0xC0)  //110xxxxx
  102.                 {
  103.                         bytes = 1;
  104.                 }
  105.                 else if ((*p & 0xF0) == 0xE0) //1110xxxx
  106.                 {
  107.                         bytes = 2;
  108.                 }
  109.                 else if ((*p & 0xF8) == 0xF0) //11110xxx
  110.                 {
  111.                         bytes = 3;
  112.                 }
  113.                 else if ((*p & 0xFC) == 0xF8) //111110xx
  114.                 {
  115.                         bytes = 4;
  116.                 }
  117.                 else if ((*p & 0xFE) == 0xFC) //1111110x
  118.                 {
  119.                         bytes = 5;
  120.                 }               
  121.                 else  //invalid char
  122.                 {
  123.                         p++;
  124.                         continue;
  125.                 }

  126.                 pSub = p + 1;
  127.                 pCharEnd = pSub + bytes;
  128.                 if (pCharEnd > pStrEnd)
  129.                 {
  130.                         p++;
  131.                         continue;
  132.                 }
  133.                 for (; pSub<pCharEnd; pSub++)
  134.                 {
  135.                         if ((*pSub & 0xC0) != 0x80)
  136.                         {
  137.                                 break;
  138.                         }
  139.                 }
  140.                 if (pSub != pCharEnd)
  141.                 {
  142.                         p++;
  143.                         continue;
  144.                 }

  145.                 bytes += 1;
  146.                 memcpy(pDest,  pSub-bytes, bytes);
  147.                 pDest += bytes;
  148.                 p += bytes;
  149.         }

  150.         *len = pDest - filtered;
  151.         memcpy(src, filtered, *len);
  152.         * (src + (*len)) = '\0';
  153.         free(filtered);
  154.         return src;
  155. }
复制代码

[ 本帖最后由 cugb_cat 于 2008-7-31 14:41 编辑 ]

论坛徽章:
0
发表于 2008-07-31 11:22 |显示全部楼层
麻烦把代码用 code 标签组织一下,给你加精华,谢谢.

论坛徽章:
4
2015年辞旧岁徽章
日期:2015-03-03 16:54:152015年迎新春徽章
日期:2015-03-04 09:56:11IT运维版块每日发帖之星
日期:2016-08-11 06:20:00IT运维版块每日发帖之星
日期:2016-08-15 06:20:00
发表于 2008-07-31 13:03 |显示全部楼层

回复 #2 converse 的帖子

重新贴一下:

/*
UTF-8 valid format list:
0xxxxxxx
110xxxxx 10xxxxxx
1110xxxx 10xxxxxx 10xxxxxx
11110xxx 10xxxxxx 10xxxxxx 10xxxxxx
111110xx 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx
1111110x 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx
*/
char *filter_none_utf8_chars(char *src, int *len)
{
        unsigned char *p;
        unsigned char *pSub;
        unsigned char *pStrEnd;
        unsigned char *pCharEnd;
        int bytes;
        unsigned char *filtered;
        unsigned char *pDest;
        unsigned char *pInvalidCharStart;

        pStrEnd = (unsigned char *)src + (*len);
        p = (unsigned char *)src;
        pInvalidCharStart = NULL;
        while (p < pStrEnd)
        {
                if (*p < 0x80)
                {
                        p++;
                        continue;
                }

                if ((*p & 0xE0) == 0xC0)  //110xxxxx
                {
                        bytes = 1;
                }
                else if ((*p & 0xF0) == 0xE0) //1110xxxx
                {
                        bytes = 2;
                }
                else if ((*p & 0xF8) == 0xF0) //11110xxx
                {
                        bytes = 3;
                }
                else if ((*p & 0xFC) == 0xF8) //111110xx

                {
                        bytes = 4;
                }
                else if ((*p & 0xFE) == 0xFC) //1111110x
                {
                        bytes = 5;
                }
                else
                {
                        pInvalidCharStart = p;
                        break;
                }

                p++;
                pCharEnd = p + bytes;
                if (pCharEnd > pStrEnd)
                {
                        pInvalidCharStart = p - 1;
                        break;
                }

                for (; p<pCharEnd; p++)
                {
                        if ((*p & 0xC0) != 0x80)
                        {
                                break;
                        }
                }

                if (p != pCharEnd)
                {
                        pInvalidCharStart = pCharEnd - (bytes + 1);
                        break;
                }
        }

        if (pInvalidCharStart == NULL) //all chars are valid
        {
                return src;
        }


        filtered = (unsigned char *)malloc(sizeof(char) * (*len));
        if (filtered == NULL)
        {
                *len = 0;
                *src = '\0';
                return src;
        }

        pDest = filtered;
        bytes = (char *)pInvalidCharStart - src;
        if (bytes > 0)
        {
                memcpy(pDest, src, bytes);
                pDest += bytes;
        }

        p = pInvalidCharStart + 1; //skip this invalid char
        while (p < pStrEnd)
        {
                if (*p < 0x80)
                {
                        *pDest++ = *p++;
                        continue;
                }

                if ((*p & 0xE0) == 0xC0)  //110xxxxx
                {
                        bytes = 1;
                }
                else if ((*p & 0xF0) == 0xE0) //1110xxxx
                {
                        bytes = 2;
                }
                else if ((*p & 0xF8) == 0xF0) //11110xxx
                {
                        bytes = 3;
                }
                else if ((*p & 0xFC) == 0xF8) //111110xx
                {
                        bytes = 4;
                }
                else if ((*p & 0xFE) == 0xFC) //1111110x
                {
                        bytes = 5;
                }               

                else  //invalid char
                {
                        p++;
                        continue;
                }

                pSub = p + 1;
                pCharEnd = pSub + bytes;
                if (pCharEnd > pStrEnd)
                {
                        p++;
                        continue;
                }

                for (; pSub<pCharEnd; pSub++)
                {
                        if ((*pSub & 0xC0) != 0x80)
                        {
                                break;
                        }
                }

                if (pSub != pCharEnd)
                {
                        p++;
                        continue;
                }

                bytes += 1;
                memcpy(pDest,  pSub-bytes, bytes);
                pDest += bytes;
                p += bytes;
        }

        *len = pDest - filtered;
        memcpy(src, filtered, *len);
        * (src + (*len)) = '\0';

        free(filtered);

        return src;
}

论坛徽章:
0
发表于 2008-07-31 13:06 |显示全部楼层
先顶下。

论坛徽章:
0
发表于 2008-07-31 13:17 |显示全部楼层
不错不错,上次还在为此事烦恼呢,先研究下

论坛徽章:
0
发表于 2008-07-31 14:29 |显示全部楼层
学习

论坛徽章:
0
发表于 2008-07-31 14:34 |显示全部楼层
怎么高效果啊,最好把测试结果贴上来撒

论坛徽章:
4
2015年辞旧岁徽章
日期:2015-03-03 16:54:152015年迎新春徽章
日期:2015-03-04 09:56:11IT运维版块每日发帖之星
日期:2016-08-11 06:20:00IT运维版块每日发帖之星
日期:2016-08-15 06:20:00
发表于 2008-07-31 14:39 |显示全部楼层

回复 #7 spiritX 的帖子

用iconv应该也可以进行过滤吧,你可以做一个对比测试,肯定比iconv的要快!
你也可以看一下LZ实现的代码

论坛徽章:
0
发表于 2008-07-31 14:42 |显示全部楼层
我给加上code标签了。

论坛徽章:
36
IT运维版块每日发帖之星
日期:2016-04-10 06:20:00IT运维版块每日发帖之星
日期:2016-04-16 06:20:0015-16赛季CBA联赛之广东
日期:2016-04-16 19:59:32IT运维版块每日发帖之星
日期:2016-04-18 06:20:00IT运维版块每日发帖之星
日期:2016-04-19 06:20:00每日论坛发贴之星
日期:2016-04-19 06:20:00IT运维版块每日发帖之星
日期:2016-04-25 06:20:00IT运维版块每日发帖之星
日期:2016-05-06 06:20:00IT运维版块每日发帖之星
日期:2016-05-08 06:20:00IT运维版块每日发帖之星
日期:2016-05-13 06:20:00IT运维版块每日发帖之星
日期:2016-05-28 06:20:00每日论坛发贴之星
日期:2016-05-28 06:20:00
发表于 2008-07-31 16:00 |显示全部楼层
原帖由 cugb_cat 于 2008-7-31 14:42 发表
我给加上code标签了。



呵呵,难怪呢。看着帖子不是斑竹发的,竟然是版主最后编辑,原来有这权限啊
您需要登录后才可以回帖 登录 | 注册

本版积分规则 发表回复

  

北京盛拓优讯信息技术有限公司. 版权所有 京ICP备16024965号-6 北京市公安局海淀分局网监中心备案编号:11010802020122 niuxiaotong@pcpop.com 17352615567
未成年举报专区
中国互联网协会会员  联系我们:huangweiwei@itpub.net
感谢所有关心和支持过ChinaUnix的朋友们 转载本站内容请注明原作者名及出处

清除 Cookies - ChinaUnix - Archiver - WAP - TOP