[占位3]繁复的字符编码问题


// GB18030 有单字节、双字节和四字节三种方式。

// 单字节 -- 0x00-0x7F

// 双字节 -- 高字节 0x81-0xFE 低字节 0x40-0x7E 0x80-0xFE

// 四字节 -- 第一、三字节 0x81-0xFE,第二、四字节 0x30-0x39



 最近,公司在XP系统于LINUX之间传数据时出现了中文乱码问题!
首先,解释一下字符集:
汉字编码:
*
GB2312字集是简体字集,全称为GB2312(80)字集,共包括国标简体汉字6763个。 *
BIG5字集是台湾繁体字集,共包括国标繁体汉字13053个。 *
GBK字集是简繁字集,包括了GB字集、BIG5字集和一些符号,共包括21003个字符。 *
GB18030是国家制定的一个强制性大字集标准,全称为GB18030-2000,它的推出使汉字集有了一个“大一统”的标准。
ASCII:

American
Standard Code for Information Interchange,美国信息交换标准码。
目前计算机中用得最广泛的字符集及其编码,由美国国家标准局(ANSI)制定。 它已被国际标准化组织(ISO)定为国际标准,称为ISO 646标准。
ASCII字符集由控制字符和图形字符组成。
在计算机的存储单元中,一个ASCII码值占一个字节(8个二进制位),其最高位(b7)用作奇偶校验位。
所谓奇偶校验,是指在代码传送过程中用来检验是否出现错误的一种方法,一般分奇校验和偶校验两种。
奇校验规定:正确的代码一个字节中1的个数必须是奇数,若非奇数,则在最高位b7添1。
偶校验规定:正确的代码一个字节中1的个数必须是偶数,若非偶数,则在最高位b7添1。
UTF:

Unicode
的实现方式不同于编码方式。
一个字符的Unicode编码是确定的,但是在实际传输过程中,由于不同系统平台的设计不一定一致,以及出于节省空间的目的,对Unicode编码的实现
方式有所不同。 Unicode的实现方式称为Unicode转换格式(Unicode Translation Format,简称为 UTF)。 *
UTF-8:
8bit变长编码,对于大多数常用字符集(ASCII中0~127字符)它只使用单字节,而对其它常用字符(特别是朝鲜和汉语会意文字),它使用3字节。
* UTF-16:
16bit编码,是变长码,大致相当于20位编码,值在0到0×10FFFF之间,基本上就是unicode编码的实现,与CPU字序有关。
注意:ASCII  char (2)  ;UTF-8 宽字符  wchar  4倍 。兼容性最好的编码就是UTF-8! 毕竟GBK/GB2312是国内的标准,当我们大量使用国外的开源软件时,UTF-8才是编码界最通用的语言。
在Linux中通过locale来设置程序运行的不同语言环境,locale由ANSI C提供支持。locale的命名规则为<语言>_<地区>.<字符集编码>,如zh_CN.UTF-8,zh代表中文,CN代表大陆地区,UTF-8表示字符集。在locale环境中,有一组变量,代表国际化环境中的不同设置:
1.    LC_COLLATE
定义该环境的排序和比较规则
2.    LC_CTYPE
用于字符分类和字符串处理,控制所有字符的处理方式,包括字符编码,字符是单字节还是多字节,如何打印等。是最重要的一个环境变量。
3.    LC_MONETARY
货币格式
4.    LC_NUMERIC
非货币的数字显示格式
5.    LC_TIME
时间和日期格式
6.    LC_MESSAGES
提示信息的语言。另外还有一个LANGUAGE参数,它与LC_MESSAGES相似,但如果该参数一旦设置,则LC_MESSAGES参数就会失效。LANGUAGE参数可同时设置多种语言信息,如LANGUANE=”zh_CN.GB18030:zh_CN.GB2312:zh_CN”。
7.    LANG
LC_*的默认值,是最低级别的设置,如果LC_*没有设置,则使用该值。类似于 LC_ALL。
8.    LC_ALL
它是一个宏,如果该值设置了,则该值会覆盖所有LC_*的设置值。注意,LANG的值不受该宏影响。
一个例子:

<span>设置前,使用默认<span>locale</span>:
</span><span>[root@db-wanggaofei ~]# locale
</span><span>LANG="POSIX"
</span><span>LC_CTYPE="POSIX"
</span><span>LC_NUMERIC="POSIX"
</span><span>LC_TIME="POSIX"
</span><span>LC_COLLATE="POSIX"
</span><span>LC_MONETARY="POSIX"
</span><span>LC_MESSAGES="POSIX"
</span><span>LC_PAPER="POSIX"
</span><span>LC_NAME="POSIX"
</span><span>LC_ADDRESS="POSIX"
</span><span>LC_TELEPHONE="POSIX"
</span><span>LC_MEASUREMENT="POSIX"
</span><span>LC_IDENTIFICATION="POSIX"
</span><span>LC_ALL=</span>

<span>设置后,使用<span>zh_CN.GDK</span>中文<span>locale</span>:</span>

<span>[root@db-wanggaofei ~]# export LC_ALL=zh_CN.GBK<br /></span><span>[root@db-wanggaofei ~]# locale<br /></span><span>LANG=zh_CN.UTF-8<br /></span><span>LC_CTYPE="zh_CN.GBK"<br /></span><span>LC_NUMERIC="zh_CN.GBK"<br /></span><span>LC_TIME="zh_CN.GBK"<br /></span><span>LC_COLLATE="zh_CN.GBK"<br /></span><span>LC_MONETARY="zh_CN.GBK"<br /></span><span>LC_MESSAGES="zh_CN.GBK"<br /></span><span>LC_PAPER="zh_CN.GBK"<br /></span><span>LC_NAME="zh_CN.GBK"<br /></span><span>LC_ADDRESS="zh_CN.GBK"<br /></span><span>LC_TELEPHONE="zh_CN.GBK"<br /></span><span>LC_MEASUREMENT="zh_CN.GBK"<br /></span><span>LC_IDENTIFICATION="zh_CN.GBK"<br /></span><span>LC_ALL=zh_CN.GBK</span>

“C”是系统默认的locale,“POSIX”是“C”的别名。所以当我们新安装完一个系统时,默认的locale就是C或POSIX。
在Debian中安装locales的方法如下:
· 通过apt-get install locales命令安装locales包
· 安装完成locales包后,系统会自动进行locale配置,你只要选择所需的locale,可以多选。最后指定一个系统默认的locale。这样系统就会帮你自动生成相应的locale和配置好系统的locale。
· 增加新的locale也很简单,用dpkp-reconfigure locales重新配置locale即可。
· 我们也可手动增加locale,只要把新的locale增加到/etc/locale.gen文件中,再运行locale-gen命令即可生成新的locale。再通过设置上面介绍的LC_*变量就可设置系统的locale了。下是一个locale.gen文件的样例。

<span><span>·<span> </span></span></span><span># This file lists locales that you wish to have built. You can find a list<br /></span><span><span>·<span> </span></span></span><span># of valid supported locales at /usr/share/i18n/SUPPORTED. Other<br /></span><span><span>·<span> </span></span></span><span># combinations are possible, but may not be well tested. If you change<br /></span><span><span>·<span> </span></span></span><span># this file, you need to rerun locale-gen.<br /></span><span><span>·<span> </span></span></span><span>#<br /></span><span><span>·</span></span><span>zh_CN.GBK GBK<br /></span><span><span>·</span></span><span>zh_CN.UTF-8 UTF-8</span>

<span>-----------------------------------------</span>

<span>在我看来只要搞清楚LANG和SUPPORTED就OK了,其他可能平时也用不太多。再参考篇文章,如下,是讲如何设置环境变量的。</span>

<span>-------------------------------------------</span>

修改 /etc/sysconfig/i18n 文件,如<br />LANG="en_US.UTF-8",xwindow会显示英文界面,<br />LANG="zh_CN.GB18030",xwindow会显示中文界面。 <br />还有一种方法 cp /etc/sysconfig/i18n $HOME/.i18n <br />修改 $HOME/.i18n 文件,如<br />LANG="en_US.UTF-8",xwindow会显示英文界面,<br />LANG="zh_CN.GB18030",xwindow会显示中文界面。<br />这样就可以改变个人的界面语言,而不影响别的用户<br /><br />修改后的/etc/sysconfig/i18n 文件为:<br />LANG="en_US.UTF-8"<br />SUPPORTED="zh_CN.GB18030:zh_CN:zh:en_US.UTF-8:en_US:en"<br />SYSFONT="latarcyrheb-sun16"<br />LC_ALL="en_US.UTF-8"<br />export LC_ALL<br /><br />设置完毕后重启或者用rc.local使生效

或修改登录用户的.bash_profile文件加入
export LANG=zh_CN.GB18030
export LANGUAGE=zh_CN.GB18030:zh_CN.GB2312:zh_CN
 
———————————————————————————————–
 
一定要知道Windows XP 是GB2312的编码,如果你的服务器字符集不是这个,估计就会是乱码,所以要调整。
 
有些人在调整的时候,说我改了系统环境变量,结果造成用户内容显示乱码,无非解决的方法就是两个:
1.用iconv转化为目前的编码
2.用你原来使用的编码
 
看了这两条,你肯定必须要明确,你原来的字符编码是如何的。说来说去,无非就是LANG SUPPORTED 和你原文件字符集的编码:)
当然了locale -a你可以看看目前系统里支持的字符集,如果不支持,还要安装奥。
如果不支持可以安装以下四个包:
  fonts-chinese-2.15-2.noarch.rpm

  fonts-ISO8859-2-1.0-14.noarch.rpm
  fonts-ISO8859-2-75dpi-1.0-14.noarch.rpm
  fonts-ISO8859-2-100dpi-1.0-14.noarch.rpm













TF-8的编码规则很简单,只有二条:

1)对于单字节的符号,字节的第一位设为0,后面7位为这个符号的unicode码。因此对于英语字母,UTF-8编码和ASCII码是相同的。

2)对于n字节的符号(n>1),第一个字节的前n位都设为1,第n+1位设为0,后面字节的前两位一律设为10。剩下的没有提及的二进制位,全部为这个符号的unicode码。

根据以上说明 下面给出一段java代码判断UTF-8格式

/**
* UTF-8编码格式判断
*
* @param rawtext
*            需要分析的数据
* @return 是否为UTF-8编码格式
*/
public static boolean isUTF8(byte[] rawtext) {
   int score = 0;
   int i, rawtextlen = 0;
   int goodbytes = 0, asciibytes = 0;
   // Maybe also use UTF8 Byte Order Mark: EF BB BF
   // Check to see if characters fit into acceptable ranges
   rawtextlen = rawtext.length;
   for (i = 0; i < rawtextlen; i++) {
    if ((rawtext[i] & (byte) 0x7F) == rawtext[i]) {
     // 最高位是0的ASCII字符
     asciibytes++;
     // Ignore ASCII, can throw off count
    } else if (-64 <= rawtext[i] && rawtext[i] <= -33
      //-0x40~-0x21
      && // Two bytes
      i + 1 < rawtextlen && -128 <= rawtext[i + 1]
      && rawtext[i + 1] <= -65) {
     goodbytes += 2;
     i++;
    } else if (-32 <= rawtext[i]
      && rawtext[i] <= -17
      && // Three bytes
      i + 2 < rawtextlen && -128 <= rawtext[i + 1]
      && rawtext[i + 1] <= -65 && -128 <= rawtext[i + 2]
      && rawtext[i + 2] <= -65) {
     goodbytes += 3;
     i += 2;
    }
   }
   if (asciibytes == rawtextlen) {

    return false;
   }
   score = 100 * goodbytes / (rawtextlen - asciibytes);
   // If not above 98, reduce to zero to prevent coincidental matches
   // Allows for some (few) bad formed sequences
   if (score > 98) {
    return true;
   } else if (score > 95 && goodbytes > 30) {
    return true;
   } else {
    return false;
   }

另外对于正规的文本文件来说UTF-8的文件开头有3个字节来标识该文本是UTF-8编码

EF, BB, BF三个字节

但通常不采用以下这种方案 因为许多文件不标准

public static boolean getByteEncode(byte[] b)
{
   if(b != null && b.length>3)
   {
    byte utf8[] = {(byte) 0xEF, (byte) 0xBB, (byte) 0xBF};
    if((b[0] == utf8[0])&&(b[1]==utf8[1])&&(b[2]==utf8[2]))
     return true;
   }
   return false;
}



public static function s_sSubString($sSrc, $iStart, $iWidth)
    {
        return preg_replace('/^(?:[\x00-\x7F]|[\xC0-\xFF][\x80-\xBF]+){0,'.$iStart.'}((?:[\x00-\x7F]|[\xC0-\xFF][\x80-\xBF]+){0,'.$iWidth.'}).*/s','\1',$sSrc);
    }

你可能感兴趣的:(字符编码)