最近在做项目时遇到导出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/
本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利。