• C# utf8编码时转换成shiftjis时出现乱码问题的处理


    最近在做项目时遇到导出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;
            }

    在调试时查看其字节编码,如图:

    image

    而239的16进制是0xef,187的16进制是0xbb,191的16进制是0xbf.

    总结

    就是查找字符串对应shift-jis编码为63时对应的byte[]字节是什么,再用Replace替换掉就OK了。如果你有什么新的发现,欢迎留言交流。

    作者:spring yang

    出处:http://www.cnblogs.com/springyangwc/

    本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利。

  • 相关阅读:
    Cocos2d-JS V3.10 一个小bug提示
    HTML5骨骼动画Demo | 使用min2d、createjs、pixi播放spine动画
    喜大普奔!Fanvas正式对外开源了,一键把Flash转为Canvas动画!移动终端动画开发不再困难。
    #回馈老读者,晒书拿学习卡#
    【关于新版Cocos2dx/Cocos2d-JS】安装包和使用方式的变化
    好消息!Html5游戏和动画的福音
    nodejs搭配phantomjs highcharts后台生成图表
    【H5动画】谈谈canvas动画的闪烁问题
    【HTTP劫持和DNS劫持】实际JS对抗
    嵌入式开发之网络通信---分布式自组网mesh。OLSR,batman,babel,aodv
  • 原文地址:https://www.cnblogs.com/springyangwc/p/2098053.html
Copyright © 2020-2023  润新知