gbk编码器_单向编码算法

gbk编码器_单向编码算法GBK、Shift-JIS、BIG5编码检测算法字符串的编码检测需要使用自定义的映射表,使用系统自带的Codepage是不大可能有准确率的,系统Codepage会将它所有没定义的字符映射为空格。GBK、Shift-JIS、BIG5的码表空间都是不连贯的,而它们的有效空间也不完全重合,这为检测编码类型提供了可能性。检测算法:1、建立字符映射表:将任一ANSI编码的所有字符

gbk编码器_单向编码算法

GBK、Shift-JIS、BIG5编码检测算法

字符串的编码检测需要使用自定义的映射表,使用系统自带的Codepage是不大可能有准确率的,系统Codepage会将它所有没定义的字符映射为空格。
GBK、Shift-JIS、BIG5的码表空间都是不连贯的,而它们的有效空间也不完全重合,这为检测编码类型提供了可能性。

检测算法:
1、建立字符映射表:将任一ANSI编码的所有字符全映射,从0×00到0xFFFF都有Unicode字符对应,但需要注意的是没有定义的字符统统映射到Unicode的0xFFFD(共三个映射表,既可用于检测也可用于转换)。
2、预设字符串的编码是Shift-JIS。
3、使用Shift-JIS的映射表从字符串第一个字符开始检测直至最后一个字符。如果遇到有字符映射到0xFFFD,设置预设编码是GBK,立刻停止步骤3,跳至步骤4。
4、如果预设编码是GBK,使用GBK的映射表从字符串第一个字符开始检测直至最后一个字符。如果遇到有字符映射到0xFFFD,设置预设编码是BIG5,立刻停止步 骤4,跳至步骤5。
5、如果预设编码是BIG5,使用BIG5的映射表从字符串第一个字符开始检测直至最后一个字符。如果遇到有字符映射到0xFFFD,设置预设编码是未知编码,立刻停止步 骤5,跳至步骤6。
6、返回预设编码。

这个算法的编码检测优先度是Shift-JIS>GBK>BIG5,也即如果顺利通过当前检测,则跳过后面所有检测。事实上,有大量字符串是能通过所有检测的。例如只有一个字符的字符串,假设这个字符是0×8140,在三个编码当中,都不会映射到Unicode的0xFFFD,因此能通过所有检测。但这没意义了。设定了优先度后是为了告诉用户最可能的一种编码。

为什么设定Shift-JIS>GBK>BIG5?
Shift-JIS的码表空间是0×00-0x7F、0xA1-0xDF、0×8140-0xFC4B
GBK的码表空间是0×00-0x7F、0×8140-0xFEFE
BIG5的码表空间是0×00-0x7F、0×8140-0xFEFE
但双字节段(0×8140以上)都不是全部已定义,Shift-JIS在0×8140以上的有效字符数是7724,GBK是21885,BIG5是19782。
GBK的覆盖面最大,有效空间基本覆盖了Shift-JIS,因此一个字符串如果能通过Shift-JIS检测,也差不多能通过GBK检测。如果将GBK的优先度设得比Shift-JIS高,那么大量真正是Shift-JIS编码的字符串就压根没机会返回给用户了。从反方向看,GBK中存在数量庞大的字符Shift-JIS没定义,Shift-JIS是高度覆盖不住GBK的,一个GBK文本从概率上没那么容易检测成Shift-JIS。也即:如果一个文本的真正编码是Shift-JIS,那么优先使用Shift-JIS检测自然不会有问题;如果它是GBK,那么优先使用Shift-JIS检测也不大会返回Shift-JIS。因此Shift-JIS应当优先于GBK。
Shift-JIS和BIG5的关系的考虑也类似。

从转换日系音乐cue、日文小说的宅用途出发,也应当将Shift-JIS设置为最高。

下面三张图是是Shift-JIS编码的小说“文学少女”と死にたがりの道化的转换结果。左边是当作本地编码的处理结果,可以无视。右边才是转换结果。
(程序和文本下载:http://code.google.com/p/unicue/downloads/detail?name=Ansi2Unicode_1.01.zip)

使用Shift-JIS映射表转换,结果自然是正确的。

强行使用GBK映射表转换,没有出现标记0xFFFD(0xFFFD:�),也即能通过GBK检测

强行使用Big5转换,出现0xFFFD标记,也即通不过BIG5检测。BIG5跟Shift-JIS的有效空间重合度没那么高,区分相对容易一点

另外一个GBK文本强行使用Shift-JIS转换的结果。很容易就出现了0xFFFD标记

那么GBK和BIG5的优先度应该谁高呢?这里就见仁见智了。GBK的字符数比BIG5多,从概率上GBK相对容易覆盖住BIG5,BIG5相对不容易覆盖住GBK。倘若采用Shift-JIS和GBK之间的比较方法,应该是BIG5的优先度比GBK高。但从实际情况来看,真正BIG5编码的文本强行使用GBK映射表转换比较容易出现0xFFFD标记,真正GBK编码的文本强行使用BIG5映射表转换反而不容易出现0xFFFD标记。

GBK文本强行使用BIG5映射表转换的结果,不容易出现0xFFFD标记

BIG5文本使用BIG5映射表转换,正常的结果

BIG5文本强行使用GBK映射表转换,很容易出现0xFFFD标记

现实结果和表面现象完全相反。如果一个文本的真正编码是GBK,那么优先使用GBK检测自然不会有问题;如果它是BIG5,那么优先使用GBK检测也不大会返回GBK。因此余倾向于GBK的优先度高于BIG5。

最后附上源代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
#define CODETYPE_DEFAULT  0
#define CODETYPE_GBK      1
#define CODETYPE_BIG5     2
#define CODETYPE_SHIFTJIS 3
#define CODETYPE_UTF8     4
#define CODETYPE_UNICODE  5
 
#define GBKOFFSET         0x8140
#define BIG5OFFSET        0x8140
#define JIS0201OFFSET     0xA1
#define JIS0201LENGTH     63
#define JIS0208OFFSET     0x8140
 
typedef
int
CodeType;
 
CodeType CheckCodeType(
const
char
* AnsiStr,
UINT
length)
{
    
if
(!AnsiStr)
        
return
CODETYPE_DEFAULT;
    
if
(length==0)
        
return
CODETYPE_DEFAULT;
 
    
//判断是否是UTF-8编码
    
UINT
i=0;
    
BOOL
isUTF8=TRUE;
    
while
(i<length)
    
{
    
......
    
}
 
    
if
(isUTF8)
        
return
CODETYPE_UTF8;
 
    
UINT
JISMapLength,GBKMapLength,BIG5MapLength;
    
char
*JISMapBuffer,*GBKMapBuffer,*BIG5MapBuffer;
    
//加载映射表
    
TCHAR
path[MAX_PATH];
//最长260
    
GetModuleFileName(NULL, path, MAX_PATH);
    
CString mapPath=CString(path);
    
int
position=mapPath.ReverseFind(
'\\'
);
    
mapPath=mapPath.Left(position);
    
CString mapFolder=mapPath;
    
CFile loadMap;
 
    
mapPath=mapFolder+_T(
"\\jis2u-little-endian.map"
);
    
if
(!loadMap.Open(mapPath,CFile::modeRead))
    
{
        
loadMap.Close();
        
::AfxMessageBox(_T(
"JIStoUnicode map loading error!"
));
        
return
CODETYPE_DEFAULT;
    
}
    
JISMapLength=loadMap.GetLength();
    
JISMapBuffer=
new
char
[JISMapLength];
    
loadMap.Read((
void
*)JISMapBuffer,JISMapLength);
    
loadMap.Close();
 
    
mapPath=mapFolder+_T(
"\\gb2u-little-endian.map"
);
    
if
(!loadMap.Open(mapPath,CFile::modeRead))
    
{
        
loadMap.Close();
        
::AfxMessageBox(_T(
"GBKtoUnicode map loading error!"
));
        
if
(JISMapBuffer)
            
delete
[]JISMapBuffer;
        
return
CODETYPE_DEFAULT;
    
}
    
GBKMapLength=loadMap.GetLength();
    
GBKMapBuffer=
new
char
[GBKMapLength];
    
loadMap.Read((
void
*)GBKMapBuffer,GBKMapLength);
    
loadMap.Close();
 
    
mapPath=mapFolder+_T(
"\\b2u-little-endian.map"
);
    
if
(!loadMap.Open(mapPath,CFile::modeRead))
    
{
        
loadMap.Close();
        
::AfxMessageBox(_T(
"Big5toUnicode map loading error!"
));
        
if
(JISMapBuffer)
            
delete
[]JISMapBuffer;
        
if
(GBKMapBuffer)
            
delete
[]GBKMapBuffer;
        
return
CODETYPE_DEFAULT;
    
}
    
BIG5MapLength=loadMap.GetLength();
    
BIG5MapBuffer=
new
char
[BIG5MapLength];
    
loadMap.Read((
void
*)BIG5MapBuffer,BIG5MapLength);
    
loadMap.Close();
 
    
//检测编码,顺序是Shift-JIS>GBK>BIG5
    
//如果通过前面编码检测,则跳过后面所有检测
    
//检查对应的Unicode字符是否为0xFFFD,文本越长,准确度越高
    
//语义分析之类是无理的了
    
CodeType strCodeType=CODETYPE_SHIFTJIS;
    
unsigned
char
low=0,high=0;
    
WCHAR
chr=0;
    
for
(i=0;i<length;)
    
{
        
memcpy
(&high,AnsiStr+i,1);
//读取第一个byte
        
i++;
        
if
(high<=0x7F) 
//ASCII码区
        
{
            
low=high;
            
high=0;
        
}
        
else
if
((high>=0xA1)&&(high<=0xDF)) 
//半角片假名区
        
{
            
low=high;
            
high=0;
        
}
        
else 
//双字节区
        
{
            
memcpy
(&low,AnsiStr+i,1);
//读取低位
            
i++;
        
}
 
        
chr=low+high*256;
        
if
(chr<0x80)
// ASCII
        
{}
        
else
if
(chr<JIS0201OFFSET)
// 0x80 - 0xA0 未定义空间
        
{
            
strCodeType=CODETYPE_DEFAULT;
// 未知编码
            
break
;
        
}
        
else
if
(chr<(JIS0201OFFSET+JIS0201LENGTH))
// 0xA1 - 0xDF 半角假名区
        
{}
        
else
if
(chr<JIS0208OFFSET)
// 0xE0 - 0x813F 未定义空间
        
{
            
strCodeType=CODETYPE_DEFAULT; 
// 未知编码
            
break
;
        
}
        
else
// 0x8140 - 0xFFFF
        
{
            
int
offset;
            
offset=chr-JIS0208OFFSET+JIS0201LENGTH;
            
memcpy
((
void
*)&chr,JISMapBuffer+offset*2,2);
            
if
(chr==0xFFFD)
            
{
                
strCodeType=CODETYPE_GBK;
                
break
;
            
}
        
}
    
}
 
    
if
(strCodeType==CODETYPE_GBK)
    
{
        
for
(i=0;i<length;)
        
{
            
memcpy
(&high,AnsiStr+i,1);
//读取第一个byte
            
i++;
            
if
(high>0x7F)
//第一个byte是高位
            
{
                
memcpy
(&low,AnsiStr+i,1);
//读取低位
                
i++;
            
}
            
else
            
{
                
low=high;
                
high=0;
            
}
 
            
chr=low+high*256;
            
if
(chr<0x80)
// ASCII码
            
{}
            
else
if
(chr<GBKOFFSET)
// 0x80 - 0x813F 未定义空间
            
{
                
strCodeType=CODETYPE_DEFAULT;  
// 未知编码
                
break
;
            
}
            
else
            
{
                
int
offset;
                
offset=chr-GBKOFFSET;
                
memcpy
((
void
*)&chr,GBKMapBuffer+offset*2,2);
                
if
(chr==0xFFFD)
                
{
                    
strCodeType=CODETYPE_BIG5;
                    
break
;
                
}
            
}
        
}
    
}
 
    
if
(strCodeType==CODETYPE_BIG5)
    
{
        
for
(i=0;i<length;)
        
{
            
memcpy
(&high,AnsiStr+i,1);
//读取第一个byte
            
i++;
            
if
(high>0x7F)
//第一个byte是高位
            
{
                
memcpy
(&low,AnsiStr+i,1);
//读取低位
                
i++;
            
}
            
else
            
{
                
low=high;
                
high=0;
            
}
 
            
chr=low+high*256;
            
if
(chr<0x80)
// ASCII码
            
{}
            
else
if
(chr<BIG5OFFSET)
// 0x80 - 0x813F 未定义空间
            
{
                
strCodeType=CODETYPE_DEFAULT;  
// 未知编码
                
break
;
            
}
            
else
            
{
                
int
offset;
                
offset=chr-BIG5OFFSET;
                
memcpy
((
void
*)&chr,BIG5MapBuffer+offset*2,2);
                
if
(chr==0xFFFD)
                
{
                    
strCodeType=CODETYPE_DEFAULT;
                    
break
;
                
}
            
}
        
}
    
}
 
    
if
(JISMapBuffer)
        
delete
[]JISMapBuffer;
    
JISMapBuffer=NULL;
    
if
(GBKMapBuffer)
        
delete
[]GBKMapBuffer;
    
GBKMapBuffer=NULL;
    
if
(BIG5MapBuffer)
        
delete
[]BIG5MapBuffer;
    
BIG5MapBuffer=NULL;
 
    
return
strCodeType;
}

映射表文件并没有从0×00持续到0xFFFF,而是采取了精简策略。
GBK和BIG5的映射表范围均是0×8140-0xFFFF(其中未定义的字符都映射到0xFFFD),转换是对0×80-0x813F的字符也都映射到0xFFFD,检测则是立刻退出。Shift-JIS的映射表由两段凑在一起,因此有两个偏移,范围是0xA1-0xDF和0×8140-0xFFFF,转换是对0×80-0xA0和0xE0-0x813F的字符也都映射到0xFFFD,检测是立刻退出。最后的还有一个检测会对0×8140-0xFFFF的字符把关。代码实现和算法略有出入,但基本一致。

http://kuyur.info/blog/archives/635

今天的文章gbk编码器_单向编码算法分享到此就结束了,感谢您的阅读,如果确实帮到您,您可以动动手指转发给其他人。

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。
如需转载请保留出处:http://bianchenghao.cn/57823.html

(0)
编程小号编程小号

相关推荐

发表回复

您的电子邮箱地址不会被公开。 必填项已用 * 标注