C# utf-8编码时转换成shift-jis时出现乱码问题的处理
最近在做项目时遇到导出CSV文件时,因客户方要求导出CSV文件一定要是shift-jis编码的CSV文件,而我们数据库存储时是unicode储存的,所以导出时会有很多?的编码,这是因为:
借住码表来解释:
|           Shift_JIS  |      |||||||||||||||||
|           0  |                   1  |                   2  |                   3  |                   4  |                   5  |                   6  |                   7  |                   8  |                   9  |                   A  |                   B  |                   C  |                   D  |                   E  |                   F  |      ||
|           00  |                   NUL  |                   SOH  |                   STX  |                   ETX  |                   EOT  |                   ENQ  |                   ACK  |                   BEL  |                   BS  |                   HT  |                   LF  |                   VT  |                   FF  |                   CR  |                   SO  |                   SI  |      |
|           10  |                   DLE  |                   DC1  |                   DC2  |                   DC3  |                   DC4  |                   NAK  |                   SYN  |                   ETB  |                   CAN  |                   EM  |                   SUB  |                   ESC  |                   FS  |                   GS  |                   RS  |                   US  |      |
|           20  |                   SP  |                   !  |                   "  |                   #  |                   $  |                   %  |                   &  |                   '  |                   (  |                   )  |                   *  |                   +  |                   ,  |                   -  |                   .  |                   /  |      |
|           30  |                   0  |                   1  |                   2  |                   3  |                   4  |                   5  |                   6  |                   7  |                   8  |                   9  |                   :  |                   ;  |                   <  |                   =  |                   >  |                   ?  |      |
|           40  |                   @  |                   A  |                   B  |                   C  |                   D  |                   E  |                   F  |                   G  |                   H  |                   I  |                   J  |                   K  |                   L  |                   M  |                   N  |                   O  |      |
|           50  |                   P  |                   Q  |                   R  |                   S  |                   T  |                   U  |                   V  |                   W  |                   X  |                   Y  |                   Z  |                   [  |                   ¥  |                   ]  |                   ^  |                   _  |      |
|           60  |                   `  |                   a  |                   b  |                   c  |                   d  |                   e  |                   f  |                   g  |                   h  |                   i  |                   j  |                   k  |                   l  |                   m  |                   n  |                   o  |      |
|           70  |                   p  |                   q  |                   r  |                   s  |                   t  |                   u  |                   v  |                   w  |                   x  |                   y  |                   z  |                   {  |                   |  |                   }  |                   ~  |                   DEL  |      |
|           80  |         |||||||||||||||||
|           90  |         |||||||||||||||||
|           A0  |                   。  |                   「  |                   」  |                   、  |                   ・  |                   ヲ  |                   ァ  |                   ィ  |                   ゥ  |                   ェ  |                   ォ  |                   ャ  |                   ュ  |                   ョ  |                   ッ  |      ||
|           B0  |                   ー  |                   ア  |                   イ  |                   ウ  |                   エ  |                   オ  |                   カ  |                   キ  |                   ク  |                   ケ  |                   コ  |                   サ  |                   シ  |                   ス  |                   セ  |                   ソ  |      |
|           C0  |                   タ  |                   チ  |                   ツ  |                   テ  |                   ト  |                   ナ  |                   ニ  |                   ヌ  |                   ネ  |                   ノ  |                   ハ  |                   ヒ  |                   フ  |                   ヘ  |                   ホ  |                   マ  |      |
|           D0  |                   ミ  |                   ム  |                   メ  |                   モ  |                   ヤ  |                   ユ  |                   ヨ  |                   ラ  |                   リ  |                   ル  |                   レ  |                   ロ  |                   ワ  |                   ン  |                   ゙  |                   ゚  |      |
|           E0  |         |||||||||||||||||
|           F0  |         
Shift_JIS是一个日本电脑系统常用的编码表。它能容纳全形及半形拉丁字母、平假名、片假名、符号及日语汉字。
它被命名为Shift_JIS的原因,是它在放置全形字符时,要避开原本在0xA1-0xDF放置的半角假名字符。
在微软及IBM的日语电脑系统中,即使用了这个编码表。这个编码表称为CP932。
字节结构
以下字元在Shift_JIS使用一个字节来表示。
ASCII字符 (0x20-0x7E),但“/”被“¥”取代
ASCII控制字符 (0x00-0x1F、0x7F)
JIS X 0201标准内的半角标点及片假名(0xA1-0xDF)
在部分操作系统中,0xA0用来放置“不换行空格”。
以下字元在Shift_JIS使用两个字节来表示。
JIS X 0208字集的所有字符
“第一位字节”使用0x81-0x9F、0xE0-0xEF (共47个)
“第二位字节”使用0x40-0x7E、0x80-0xFC (共188个)
使用者定义区
“第一位字节”使用0xF0-0xFC (共47个)
“第二位字节”使用0x40-0x7E、0x80-0xFC (共188个)
在Shift_JIS编码表中,并未使用0xFD、0xFE及0xFF。
在微软及IBM的日语电脑系统中,在0xFA、0xFB及0xFC的两字节区域,加入了388个JIS X 0208没有收录的符号和汉字。
因为unicode的很多编码而shift-jis并没有用到,所以在转换时shift-jis没有对应的编码转换,所以转换成byte时都是以63来代替,即是?显示出来,因些我们要跟据原来字符串的字节码所对应的字符替换成shift-jis能显的相应字符。
我们的设计思路如下:
1、用一张转换表来处理保存要替换的编码表和字符表。
2、用两种处理方式来处理转换代码。
a:用编码来替换,有些特殊字符并没显示出字符串,但是他却是存在的,如空字符,0xa0,shift-jis里并没有对应的编码。还有一些特殊字符,如utf-8是new byte[] {0xef, 0xbb,0xbf}的空字符串。
b:在字符串转换前替换掉。如一些明显可保存的字付串。如〜替换成~,直接Replace替换掉.
问题就会随之而来,我们在表时只能保存像 0xef, 0xbb,0xbf 这样的字符串,怎么样转换成new byte[] {0xef, 0xbb,0xbf}呢?
我们处理的方式如下:
        private byte[] ConvertStringToByte(string originalStr)
        {
            if (string.IsNullOrEmpty(originalStr)) return null;
            string[] originalSplit = originalStr.Split(',');            
            int originalFirstValue = 0, originalSecondValue = 0, originalThirdValue = 0;
            byte[] resultByte;
            originalFirstValue = Convert.ToInt32(originalSplit[0].Trim(), 16);
            if (originalSplit.Length == 2)
            {
                originalSecondValue = Convert.ToInt32(originalSplit[1].Trim(), 16);
                resultByte = new byte[] { BitConverter.GetBytes(originalFirstValue)[0], BitConverter.GetBytes(originalSecondValue)[0] };
            }
            else  if (originalSplit.Length == 3)
            {
                originalSecondValue = Convert.ToInt32(originalSplit[1].Trim(), 16);
                originalThirdValue = Convert.ToInt32(originalSplit[2].Trim(), 16);
                resultByte = new byte[] { BitConverter.GetBytes(originalFirstValue)[0], BitConverter.GetBytes(originalSecondValue)[0], BitConverter.GetBytes(originalThirdValue)[0] };
            }
            else
            {
                resultByte = new byte[] { BitConverter.GetBytes(originalFirstValue)[0] };
            }
            return resultByte;
        }
根据传入的代码转换成相应字节流。而后概据我们的处理逻辑编写代码进行替换。
代码如下:
       public string ReplaceString(string content)
        {
            List<MessyCodeHandleBE> messyCodeHandleBEList = RetrieveAll();
            foreach (MessyCodeHandleBE entity in messyCodeHandleBEList)
            {
                if (entity.ConvertType == MessyCodeHandleConvertTypeChoices.ENCODEREPLACE)
                {
                    content = content.Replace(Encoding.UTF8.GetString(ConvertStringToByte(entity.OriginalCode)), entity.ReplaceCode);
                }
                else
                {
                    content = content.Replace(entity.OriginalCode, entity.ReplaceCode);
                }
            }
            return content;
        }
而一个特殊字符的编码如何取得可以跟据以下代码自己计算,代码如下:
        private string ConvertToShiftJis(string content)
        {
            Encoding orginal = Encoding.GetEncoding("utf-8");
            Encoding ShiftJis = Encoding.GetEncoding("Shift-JIS");
            byte[] unf8Bytes = orginal.GetBytes(content);
            byte[] myBytes = Encoding.Convert(orginal, ShiftJis, unf8Bytes);
            string JISContent = ShiftJis.GetString(myBytes);
            return JISContent;
        }
在调试时查看其字节编码,如图:
而239的16进制是0xef,187的16进制是0xbb,191的16进制是0xbf.
总结
就是查找字符串对应shift-jis编码为63时对应的byte[]字节是什么,再用Replace替换掉就OK了。如果你有什么新的发现,欢迎留言交流。
作者:spring yang
出处:http://www.cnblogs.com/springyangwc/
本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利。
作者: spring yang 发表于 2011-07-05 10:41 原文链接
