C# utf8编码时转换成shiftjis时出现乱码问题的处理
最近在做项目时遇到导出CSV文件时,因客户方要求导出CSV文件一定要是shift-jis编码的CSV文件,而我们数据库存储时是unicode储存的,所以导出时会有很多?的编码,这是因为:
借住码表来解释:
Shift_JIS
A
B
C
D
E
F
NUL
SOH
STX
ETX
EOT
ENQ
ACK
BEL
BS
HT
LF
VT
FF
CR
SO
SI
DLE
NAK
SYN
ETB
CAN
EM
SUB
ESC
FS
GS
RS
US
SP
!
"
#
$
%
&
'
(
)
*
+
,
-
.
/
:
;
<
=
>
?
@
A
B
C
D
E
F
G
H
I
J
K
L
M
N
O
P
Q
R
S
T
U
V
W
X
Y
Z
[
¥
]
^
_
`
a
b
c
d
e
f
g
h
i
j
k
l
m
n
o
p
q
r
s
t
u
v
w
x
y
z
{
|
}
~
DEL
?
?
?
?
?
?
?
?
?
?
?
?
?
?
?
?
?
?
?
?
?
?
?
?
?
?
?
?
?
?
?
?
?
?
?
?
?
?
?
?
?
?
?
?
?
?
?
?
?
?
?
?
?
?
?
?
?
?
?
?
?
?
?
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}呢?
我们处理的方式如下:
01 private byte [] ConvertStringToByte( string originalStr)
02 {
03 if ( string .IsNullOrEmpty(originalStr)) return null ;
04 string [] originalSplit = originalStr.Split( ',' );
05 int originalFirstValue = 0, originalSecondValue = 0, originalThirdValue = 0;
06 byte [] resultByte;
07 originalFirstValue = Convert.ToInt32(originalSplit[0].Trim(), 16);
08 if (originalSplit.Length == 2)
09 {
10 originalSecondValue = Convert.ToInt32(originalSplit[1].Trim(), 16);
11 resultByte = new byte [] { BitConverter.GetBytes(originalFirstValue)[0], BitConverter.GetBytes(originalSecondValue)[0] };
12 }
13 else if (originalSplit.Length == 3)
14 {
15 originalSecondValue = Convert.ToInt32(originalSplit[1].Trim(), 16);
16 originalThirdValue = Convert.ToInt32(originalSplit[2].Trim(), 16);
17 resultByte = new byte [] { BitConverter.GetBytes(originalFirstValue)[0], BitConverter.GetBytes(originalSecondValue)[0], BitConverter.GetBytes(originalThirdValue)[0] };
18 }
19 else
20 {
21 resultByte = new byte [] { BitConverter.GetBytes(originalFirstValue)[0] };
22 }
23 return resultByte;
24 }
根据传入的代码转换成相应字节流。而后概据我们的处理逻辑编写代码进行替换。
代码如下:
01 public string ReplaceString( string content)
02 {
03 List<MessyCodeHandleBE> messyCodeHandleBEList = RetrieveAll();
04
05 foreach (MessyCodeHandleBE entity in messyCodeHandleBEList)
06 {
07 if (entity.ConvertType == MessyCodeHandleConvertTypeChoices.ENCODEREPLACE)
08 {
09 content = content.Replace(Encoding.UTF8.GetString(ConvertStringToByte(entity.OriginalCode)), entity.ReplaceCode);
10 }
11 else
12 {
13 content = content.Replace(entity.OriginalCode, entity.ReplaceCode);
14 }
15 }
16 return content;
17 }
而一个特殊字符的编码如何取得可以跟据以下代码自己计算,代码如下:
1 private string ConvertToShiftJis( string content)
2 {
3 Encoding orginal = Encoding.GetEncoding( "utf-8" );
4 Encoding ShiftJis = Encoding.GetEncoding( "Shift-JIS" );
5 byte [] unf8Bytes = orginal.GetBytes(content);
6 byte [] myBytes = Encoding.Convert(orginal, ShiftJis, unf8Bytes);
7 string JISContent = ShiftJis.GetString(myBytes);
8 return JISContent;
9 }
在调试时查看其字节编码,如图:
而239的16进制是0xef,187的16进制是0xbb,191的16进制是0xbf.
总结
就是查找字符串对应shift-jis编码为63时对应的byte[]字节是什么,再用Replace替换掉就OK了。如果你有什么新的发现,欢迎留言交流。
作者: spring yang
出处: http://www.cnblogs.com/springyangwc/
本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利。
作者: Leo_wl
出处: http://www.cnblogs.com/Leo_wl/
本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利。
版权信息查看更多关于C# utf8编码时转换成shiftjis时出现乱码问题的处理的详细内容...