免费注册 查看新帖 |

Chinaunix

  平台 论坛 博客 文库
最近访问板块 发新帖
查看: 5466 | 回复: 9
打印 上一主题 下一主题

解决数据库系统中存在的半个汉字问题 [复制链接]

论坛徽章:
0
跳转到指定楼层
1 [收藏(0)] [报告]
发表于 2009-03-26 14:30 |只看该作者 |倒序浏览
我们的汉字在计算机系统里面存储时需要2个字节的空间。当数据库使用单字节字符集的时候,数据库允许存储半个汉字,因为它占用的是一个字节的空间为一个有效数据,例如通常的英文字符集:en_us.819或en_us.utf8。但是当数据库使用多字节字符集的时候,由于半个汉字为非法的不完整字符,会导致数据库在存储这种数据的时候报错illegal character,例如通常的中文字符集:zh_cn.gb和zh_cn.GB18030-2000。为了解决这个问题,我编写了一个小程序用于过滤掉数据库数据中存在的半个汉字问题。

原理:
汉字由2个字节组成,且每个部分其ascii编码都大于127,因此我们在发现一个字符的ascii编码大小大于127的情况下需要检测紧随的一个字节其ascii编码是否大于127,如果是则为一个完整的汉字,反之则是半个汉字。

以下为使用步骤:
1.将数据库中的数据卸载为存文本形式
2.使用trim infile outfile对该数据进行过滤,它会将所有紧跟中非中文字符的半个汉字去除
3.设置中文字符集以后,将该数据重新装载进数据库


/*******************************************************************************
*
*       Module:         trim
*       Author:         Richard ZHAN
*       Description:    Eliminate half Chinese character followed by a non Chinese character in a plain data file
*
*       Change Log
*
*       Date            Name            Description.................
*       03/20/2009      Richard ZHAN    Start Program
*
*******************************************************************************/

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <errno.h>
#include <strings.h>

#define LEN 4096

int
main (int argc, char *argv[])
{
  int rfd, wfd, len1, len2, i;
  char hi, *p1, *p2, str1[LEN], str2[LEN];
  unsigned char ascii_hi = '\x7F';

  if (argc != 3)
    {
      usage ();
      exit (1);
    }
  if ((rfd = open (argv[1], O_RDONLY)) == -1)
    {
      printf ("Cannot open read file!\n");
      exit (1);
    }
  else if ((wfd = open (argv[2], O_RDWR | O_CREAT, 0644)) == -1)
    {
      printf ("Cannot open write file!\n");
      close (rfd);
      exit (1);
    }
  else
    {
      hi = '\x0';
      while ((len1 = read (rfd, str1, LEN)) > 0)
        {
          len2 = 0;
          bzero (str2, LEN);
          p2 = str2;
          for (p1 = str1, i = 0; i < len1; p1++, i++)
            {
              if ((unsigned char) (*p1) > ascii_hi)
                {
                  if (hi == '\x0')
                    {
                      hi = *p1;
                    }
                  else
                    {
                      *p2++ = hi;
                      *p2++ = *p1;
                      len2 += 2;
                      hi = '\x0';
                    }
                }
              else
                {
                  *p2++ = *p1;
                  len2++;
                  hi = '\x0';
                }
            }
          if (write (wfd, str2, len2) != len2)
            {
              perror ("Encounter write error\n");
              close (rfd);
              close (wfd);
              exit (1);
            }
        }
      if (len1 < 0)
        {
          perror ("Encounter read error\n");
          close (rfd);
          close (wfd);
          exit (1);
        }
    }
  close (rfd);
  close (wfd);
  exit (0);
}

usage ()
{
  fprintf (stderr, "Usage: trim infile outfile\n");
  return 0;
}

论坛徽章:
0
2 [报告]
发表于 2009-03-26 18:22 |只看该作者
不好意思,你这个原理是不正确的,很多汉字的后半部分ascII码是小于127的。

论坛徽章:
0
3 [报告]
发表于 2009-03-26 18:33 |只看该作者

回复 #2 xxyyy 的帖子

是否能举例说明一下,谢谢!

论坛徽章:
0
4 [报告]
发表于 2009-03-27 08:28 |只看该作者
GB 18030的双字节部分完全采用了GBK的内码系统。在此基础上,做了四字节扩展,四个字节的编码空间依次是:0x81到0xFE,0x30到0x39,0x81到0xFE,0x30到0x39。总共1,587,600个码位。
所以,你的这种判断方法只适应于GB2312,判断GBK字符时都会出错

论坛徽章:
11
金牛座
日期:2015-03-19 16:56:22数据库技术版块每日发帖之星
日期:2016-08-02 06:20:00数据库技术版块每日发帖之星
日期:2016-04-24 06:20:00数据库技术版块每日发帖之星
日期:2016-04-13 06:20:00IT运维版块每日发帖之星
日期:2016-04-13 06:20:00数据库技术版块每日发帖之星
日期:2016-02-03 06:20:00数据库技术版块每日发帖之星
日期:2015-08-06 06:20:00季节之章:春
日期:2015-03-27 15:54:57羊年新春福章
日期:2015-03-27 15:54:37戌狗
日期:2015-03-19 16:56:41数据库技术版块每日发帖之星
日期:2016-08-18 06:20:00
5 [报告]
发表于 2009-03-27 10:15 |只看该作者
我是看不懂啦~~

论坛徽章:
0
6 [报告]
发表于 2009-03-28 18:44 |只看该作者

回复 #4 whitecat 的帖子

谢谢指教!那是否方便告知有没有什么切实可行的方法对不同的GB编码系统都能适用呢,无论何种编码都能准确判断出是有效汉字?请不吝赐教!

论坛徽章:
0
7 [报告]
发表于 2009-03-28 20:28 |只看该作者
GBK范围:
1st byte                     2nd byte
0x81~0xfe   0x40~0x7e and 0x80~0xfe

论坛徽章:
0
8 [报告]
发表于 2009-03-29 18:30 |只看该作者

回复 #7 MicroHard 的帖子

那如果是这样要是遇到半个字符岂不是无法根据字符的ascii数值来进行判断?

论坛徽章:
0
9 [报告]
发表于 2009-04-05 01:12 |只看该作者
镕E946

论坛徽章:
0
10 [报告]
发表于 2009-04-09 11:11 |只看该作者
可以参考一下这个帖子
http://bbs2.chinaunix.net/thread-429236-1-1.html
您需要登录后才可以回帖 登录 | 注册

本版积分规则 发表回复

  

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

清除 Cookies - ChinaUnix - Archiver - WAP - TOP