分享
 
 
 

乱码算法大全

王朝other·作者佚名  2006-01-08
窄屏简体版  字體: |||超大  

乱码算法大全

相信上过网的朋友们都遇见过“乱码”,也就是在浏览网页或看Email时出现的不能辨认的字符。以前也有许多的文章介绍过“乱码”,不过他们的文章只是讲怎样辨别和怎样用工具解码,并没有详细介绍各种编码的算法的实现,本文将对互联网上最常用的几种编码的编码和解码算法作以详细的阐述。希望对想了解“乱码”算法或想在自己程序中实现这些功能朋友们有一些参考价值。本文的源程序用C语言写成,形式为函数,可直接使用。

一. 常用编码

1. Uuencode

Uuencode 是将二进制文件以文本文件方式进行编码表示、以利于基于文本传输环境中进行二进制文件的传输/交换的编码方法之一, 在邮件系统/二进制新闻组中使用频率比较高,经常用于 Attach 二进制文件。

这种编码的特征是:每一行开头用“M”标志。下面是我做的一个测试用的文件mogao.txt,编码为Uuencode:

begin 644 mogao.txt

M"0D)("`@(*&VPM+"ZOCMZBT\BKH;<-"@G7]]7?.FUO9V%OHZRPU]3&N:Z

MU]6^HZAT96QN970Z+R\R,#(N,3$R+C(P+C$S,CHR,Z.IL\G4L:&C#0H)("`@

M("`@Q*JXWCMO/ZYI-?WRM*CNFAT='`Z+R]M;V=A;RYB96YT:75N+FYE=`T*

M"0D)16UA:6QT;SIM;V=A;T`S-S$N;F5T#0H)("`@*BHJ*BHJ*BHJ*BHJ*BHJ

M*BHJ*BHJ*BHJ*BHJ*BHJ*BHJ*BHJ*BHJ*BHJ*BHJ("`@("`@("`@("`@("`@

M#0H)("`@*B"S_<'+O,?2Y,JRP[2VO+*[M/C7WZ.LL_W!R]?CO*/*LL.TMKRR

MN\'TS\(J#0H)("`@*BHJ*BHJ*BHJ*BHJ*BHJ*BHJ*BHJ*BHJ*BHJ*BHJ*BHJ

,*BHJ*BHJ*BHJ*BHJ

`

end

你可以把它单独存成一个文件:mogao.uue,然后用Winzip打开,解压即得mogao.txt。

Uuencode的算法很简单,编码时它将3个字符顺序放入一个 24 位的缓冲区,缺字符的地方补零,然后将缓冲区截断成为 4 个部分,高位在先,每个部分 6 位,用下面的64个字符重新表示:

"`!"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_"

在文件的开头有“begin xxx 被编码的文件名”,在文件的结尾有“end”,用来标志Uue文件的开始和结束。编码时,每次读取源文件的45个字符,不足45个的用“NULL”补足为3的整数倍(如:23补为24),然后输入目标文件一个ASCII为:“32+实际读取的字符数”的字符作为每一行的开始。读取的字符编码后输入目标文件,再输入一个“换行符”。如果源文件被编码完了,那么输入“`(ASCII为96)”和一个“换行符”表示编码结束。

解码时它将4个字符分别转换为4个6位字符后,截取有用的后六位放入一个 24 位的缓冲区,即得3个二进制代码。

下面我给出Uuencode编码和解码的C语言描述:

/*Uuencode编码*/

void Uue(unsigned char chasc[3],unsigned char chuue[4])

/*

chasc:未编码的二进制代码

chuue:编码过的Uue代码

*/

{int i,k=2;

unsigned char t=NULL;

for(i=0;i<3;i++)

{*(chuue+i)=*(chasc+i)>>k;

*(chuue+i)|=t;

if(*(chuue+i)==NULL) *(chuue+i)+=96;

else *(chuue+i)+=32;

t=*(chasc+i)<<(8-k);

t>>=2;

k+=2;

}

*(chuue+3)=*(chasc+2)&63;

if(*(chuue+3)==NULL) *(chuue+3)+=96;

else *(chuue+3)+=32;

}

/*Uuencode解码*/

void unUue(unsigned char chuue[4],unsigned char chasc[3])

/*

chuue:未解码的Uue代码

chasc:解码过的二进制代码

*/

{int i,k=2;

unsigned char t=NULL;

if(*chuue==96) *chuue=NULL;

else *chuue-=32;

for(i=0;i<3;i++)

{*(chasc+i)=*(chuue+i)<<k;

k+=2;

if(*(chuue+i+1)==96) *(chuue+i+1)=NULL;

else *(chuue+i+1)-=32;

t=*(chuue+i+1)>>8-k;

*(chasc+i)|=t;

}

}

2. Xxencode

提到Uuencode不可能不提Xxencode, Xxencode的编码算法和 Uuencode基本相同,但是使用的是不同的字符集。XxEncode编码使用的字符是:

“+-0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz”与 Uuencode 相比,它的特殊字符更少。很多支持 Uuencode 编解码的工具都同时支持 Xxencode。

这种编码的特征是:每一行开头用“h”标志。下面是Xxencode的一个例子:

begin 644 mogao.txt

h0EY760+U684qkh90uwjXhuWowwWfcPQB0UbLxxLTCapjNq3jcumkpxH4iwOu

hpxKycuVoNKliNLEu9mwmA16iAH2m9X6k9X2nAXcmAuCdgwbIgO4X1Ec760+U

h60+Ul8esrwXhjDutdBTrmh8XiaVoR5+u9mxhPqRVPmtWNKtoOLJi9atZR+o8

h0EY7FKpVOKloPndhPqRVPo+nBn2iPaJo1Ec760+U8Wce8Wce8Wce8Wce8Wce

h8Wce8Wce8Wce8Wce8Wce8Wce8Wce8Wce8Wce8Wce60+U60+U60+U60+U60+U

h1Ec760+U8W0nzQ59jATGtAemkvGqj98vhDXLruCggzr-mxTXj8D8ggCohfmm

hiw5onw6e1Ec760+U8Wce8Wce8Wce8Wce8Wce8Wce8Wce8Wce8Wce8Wce8Wce

A8Wce8Wce8Wce8Wce

+

end

你可以把它单独存成一个文件:mogao.xxe,然后用Winzip打开,解压即得mogao.txt。

Xxencode的编码算法和Uuencode基本相同,实现起来则更为简单,在此就不详述了。

下面给出Xxencode编码和解码的C语言描述:

/*Xxencode编码*/

void Xxe(unsigned char chasc[3],unsigned char chxxe[4])

/*

chasc:未编码的二进制代码

chxxe:编码过的Xxe代码

*/

{int i;

static char set[]=

"+-0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";

chxxe[0]=chasc[0]>>2;

chxxe[1]=(chasc[0]<<4)&48|(chasc[1]>>4)&15;

chxxe[2]=(chasc[1]<<2)&60|(chasc[2]>>6)&3;

chxxe[3]=chasc[2]&63;

for(i=0;i<4;i++) chxxe[i]=set[chxxe[i]]; /*查表*/

}

/*需注意的是,Xxencode文件正文部分中每一行的第一个字母是:从源文件中实际 读取的字符数的ASCII值取后六位后用set[]查表得到的。*/

/*Xxencode解码*/

unsigned char set(unsigned char ch) /*查表函数*/

{if(ch==43) ch=0;

else if(ch==45) ch=1;

else if(ch>=48&&ch<=57) ch-=46;

else if(ch>=65&&ch<=90) ch-=53;

else if(ch>=97&&ch<=122) ch-=59;

return ch;

}

void unXxe(unsigned char chxxe[4],unsigned char chasc[3])

/*

chxxe:未解码的Xxe代码

chasc:解码过的二进制代码

*/

{int k=2 ,i;

unsigned char t;

t=NULL;

*chxxe=set(*chxxe);

for(i=0;i<3;i++)

{*(chxxe+i+1)=set(*(chxxe+i+1));

(chhex+i)=*(chxxe+i)<<k;

k+=2;

t=*(chxxe+i+1)>>8-k;

*(chhex+i)|=t;

}

}

3. Base64

Base64和下面将要介绍的Quoted-Printable都属于MIME(多部分( multi-part)、多媒体电子邮件和 WWW 超文本的一种编码标准,用于传送诸如图形、声音和传真等非文本数据)。MIME定义在RFC1341中。

Base64是现今在互联网上应用最多的一种编码,几乎所有的电子邮件软件头把它作为默认的二进制编码,它已经成了现今电子邮件编码的代名词。

下面是Base64的一个例子,从例子中,您也可以看到Base64与电子邮件的的紧密联系:

Content-Type: text/plain;charset="cn-gb"

Content-Transfer-Encoding: BASE64

CQkJICAgIKG2wtLC68vjt6i088irobcNCgnX99XfOm1vZ2Fvo6yw19TGu8a619W+o6h0ZWxuZXQ6

Ly8yMDIuMTEyLjIwLjEzMjoyM6Ops8nUsaGjDQoJICAgICAgxKq438jtvP65pNf3ytKjumh0dHA6

Ly9tb2dhby5iZW50aXVuLm5ldA0KCQkJRW1haWx0bzptb2dhb0AzNzEubmV0DQoJICAgKioqKioq

KioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqICAgICAgICAgICAgICAgDQoJ

ICAgKiCz/cHLvMfS5Mqyw7S2vLK7tPjX36Oss/3By9fjvKPKssO0tryyu8H0z8IqDQoJICAgKioq

KioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioq

你可以把它单独存成一个文件,可以取名为:mogao.eml,双击可以用OutLook打开(前两行为邮件的原始信息,从第四行开始为编码内容)。

Base64的算法同Uuencode的算法很接近,也很简单:它将字符流顺序放入一个 24 位的缓冲区,缺字符的地方补零。然后将缓冲区截断成为 4 个部分,高位在先,每个部分 6 位,用下面的64个字符重新表示:“ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/”。如果输入只有一个或两个字节,那么输出将用等号“=”补足。这可以隔断附加的信息造成编码的混乱。它每行一般为76个字符。

下面我给出Base64的编码和解码的C语言描述:

/*Base64编码*/

void Base64(unsigned char chasc[3],unsigned char chuue[4])

/*

chasc:未编码的二进制代码

chuue:编码过的Base64代码

*/

{

int i,k=2;

unsinged char t=NULL;

for(i=0;i<3;i++)

{

*(chuue+i)=*(chasc+i)>>k;

*(chuue+i)|=t;

t=*(chasc+i)<<(8-k);

t>>=2;

k+=2;

}

*(chuue+3)=*(chasc+2)&63;

for(i=0;i<4;i++)

if((*(chuue+i)>=0)&&(*(chuue+i)<=25)) *(chuue+i)+=65;

else if((*(chuue+i)>=26)&&(*(chuue+i)<=51)) *(chuue+i)+=71;

else if((*(chuue+i)>=52)&&(*(chuue+i)<=61)) *(chuue+i)-=4;

else if(*(chuue+i)==62) *(chuue+i)=43;

else if(*(chuue+i)==63) *(chuue+i)=47;

}

/*Base64解码*/

void unBase64(unsigned char chuue[4],unsigned char chasc[3])

/*

chuue:未解码的Base64代码

chasc:解码过的二进制代码

*/

{int i,k=2;

unsigned char t=NULL;

for(i=0;i<4;i++)

if((*(chuue+i)>=65)&&(*(chuue+i)<=90)) *(chuue+i)-=65;

else if((*(chuue+i)>=97)&&(*(chuue+i)<=122)) *(chuue+i)-=71;

else if((*(chuue+i)>=48)&&(*(chuue+i)<=57)) *(chuue+i)+=4;

else if(*(chuue+i)==43) *(chuue+i)=62;

else if(*(chuue+i)==47) *(chuue+i)=63;

else if(*(chuue+i)==61) *(chuue+i)=0;

for(i=0;i<3;i++)

{*(chhex+i)=*(chuue+i)<<k;

k+=2;

t=*(chuue+i+1)>>8-k;

*(chhex+i)|=t;

}

}

4. Quoted-Printable

Quoted-Printable简称QP, 一般用在Email系统中。它通常用于少量文本方式的8位字符的编码,例如Foxmail就用它做对主题和信体的编码。这种编码的应该是很好辨认的:它有大量的“=”。下面是它的一个例子:

Mime-Version: 1.0

Content-Transfer-Encoding: quoted-printable

=A1=B6=C2=D2=C2=EB=CB=E3=B7=A8=B4=F3=C8=AB=A1=B7

=D7=F7=D5=DF:mogao=A3=AC=B0=D7=D4=C6=BB=C6=BA=D7=D5=BE=A3=A8telnet://202.112.20.132:23=A3=A9=B3=C9=D4=B1=A1=A3

=C4=AA=B8=DF=C8=ED=BC=FE=B9=A4=D7=F7=CA=D2=A3=BAhttp://mogao.bentiun.net

Emailto:mogao@371.net

*********************************************

* =B3=FD=C1=CB=BC=C7=D2=E4=CA=B2=C3=B4=B6=BC=B2=BB=B4=F8=D7=DF=A3=AC=B3=FD=C1=CB=D7=E3=BC=A3=CA=B2=C3=B4=B6=BC=B2=BB=C1=F4=CF=C2*

*********************************************

你可以把它单独存成一个文件,取名为:mogao.eml,双击可以用OutLook打开(前两行为邮件的原始信息,从第四行开始为编码内容)。

QP的算法可以说是最简单的也可以说是编码效率最低的(它的编码率是1:3),它是专门为了处理8位字符制定的。它的算法是:读一个字符,如果ASCII码大于127,即字符的第8位是1的话,进行编码,否则忽略(有时也对7位字符编码)。编码很简单,看下面的C语言描述即可:

/*QP编码*/

void qp(unsigned char sour,unsigned char first,unsigned char second)

/*

sour:要编码的字符

first:编码后的第一个字符

second:编码后的第二个字符

first和second为返回值

*/

{

if(sour>127)

{first=sour>>4;

second=sour&15;

if(first>9) first+=55;

else first+=48;

if(second>9) second+=55;

else second+=48;

printf("%c%c%c",'=',first,second);

}

}

/*QP解码*/

void uqp(unsigned char sour,unsigned char first,unsigned char second)

/*

sour:解码后的字符

first:QP码的第一个字符

second:QP码的第二个字符

sour为返回值

*/

{

if(first>=65) first-=55;

else first-=48;

if(second>=65) second-=55;

else second-=48;

sour=NULL;

sour=first<<4;

sour|=second;

}

现在大家知道为什么QP的编码率那么低了吧!关于QP的详细说明和准确定义可以参阅RFC2045。

二.汉字编码

1. GB码和Big5码

GB码是中国大陆、新加坡等国家和地区使用的一种汉字编码方法。Big5码是中国台湾省用的一种汉字编码方法。它们的编码方法是完全不同的两种方法,它们之间的转换只能通过“查表法”来进行。所以说转换的方法很简单,困难的是“表”的生成。很多文章对此都做过介绍,我在此就不详述了。在我的主页上有我写的“汉字转码通V1.0”的源程序,其中有这两个“表”,可以直接使用。

2. HZ码

HZ码是为了使只能传送7bit信息的邮件服务器或网关能传送8bit信息而定义的编码,也是中文常用编码的一种。它和上面介绍的Quoted-Printable码都只能对文本进行编码,即编码时忽略控制字符。

这种编码的也是很好辨认的:有许多“~{”和“~}”,而且总是成对出现。下面是HZ码的一个例子:

~{!6BRBkKc7(4sH+!7~}

~{WwU_~}:mogao~{#,0WTF;F:WU>#(~}telnet://202.112.20.132:23~{#)3IT1!#~}

~{D*8_Hm<~9$WwJR#:~}http://mogao.bentiun.net

Emailto:mogao@371.net

*********************************************

* ~{3}AK<GRdJ2C46<2;4xW_#,3}AKWc<#J2C46<2;AtOB~}*

*********************************************

您可以打开“南极星”看这段文字。

它的算法更简单:读一个字符,如果是8位字符,就把它的最高位清零。把连续的8位字符清零后的输出用“~{”和“~}”括起来。解码时:把是用“~{”和“~}”括起来的部分每个字符的第8位置“1”即可。

上面介绍的三种编码之间的转换是经常遇见的,我写的“汉字转码通V1.0”可以方便的在这三种之间转换,我把它的源程序公开,方便广大网友的学习。

三.其他常用编码

1. Unicode

Unicode应用中最典型的例子是:IE4以上版本对HTML的编码。它可以说是未来Windows下唯一的字符集。但它还很不完善,而且Win95和Win98对它的支持还很有限,甚至它还没有一套完整的标准。不过,微软最新推出的Office2000和马上就要推出的Windows2000将全面支持Unicode。Unicode取代其他编码将会是必然的趋势。不过,在近一两年Unicode并不会占主导地位,就是在占主导地位后,因为操作系统的差异,其他编码也不会立即消亡。它的中文资料可以在Office2000和Windows2000所带的文档中找到,它的官方网站是:http://www.unicode.org/。

2. Binhex

BinHex 编码是 Macintosh 计算机(也就是俗称的“苹果电脑”)上用可打印字符表示/传输二进制文件的一种编码方法。它的主要用途是在电子邮件程序中Attach二进制文件。大部分的电子邮件程序不支持这种格式(Eudora支持),但用WINZIP可以进行解码。它的资料请查阅Macintosh计算机带的相关文档。

三.总结

由于篇幅所限,除了本文介绍的这几种常用编码外,还是有很多种编码的。如各种加密算法产生的“乱码”(我将在另外一篇文章中详细介绍)。本文中提到的所有文档和源程序在我的主页中均可下载,我的主页地址是:http://mogao.bentium.net。如果您对本文有什么意见请来信商榷,我的E-mail地址是:mogao@371.net。

注:我在本文中使用的例子“mogao.txt”的内容是:

《乱码算法大全》

作者:mogao,白云黄鹤站(telnet://202.112.20.132:23)成员。

莫高软件工作室:http://mogao.bentiun.net

Emailto:mogao@371.net

*********************************************

* 除了记忆什么都不带走,除了足迹什么都不留下*

*********************************************

 
 
 
免责声明:本文为网络用户发布,其观点仅代表作者个人观点,与本站无关,本站仅提供信息存储服务。文中陈述内容未经本站证实,其真实性、完整性、及时性本站不作任何保证或承诺,请读者仅作参考,并请自行核实相关内容。
2023年上半年GDP全球前十五强
 百态   2023-10-24
美众议院议长启动对拜登的弹劾调查
 百态   2023-09-13
上海、济南、武汉等多地出现不明坠落物
 探索   2023-09-06
印度或要将国名改为“巴拉特”
 百态   2023-09-06
男子为女友送行,买票不登机被捕
 百态   2023-08-20
手机地震预警功能怎么开?
 干货   2023-08-06
女子4年卖2套房花700多万做美容:不但没变美脸,面部还出现变形
 百态   2023-08-04
住户一楼被水淹 还冲来8头猪
 百态   2023-07-31
女子体内爬出大量瓜子状活虫
 百态   2023-07-25
地球连续35年收到神秘规律性信号,网友:不要回答!
 探索   2023-07-21
全球镓价格本周大涨27%
 探索   2023-07-09
钱都流向了那些不缺钱的人,苦都留给了能吃苦的人
 探索   2023-07-02
倩女手游刀客魅者强控制(强混乱强眩晕强睡眠)和对应控制抗性的关系
 百态   2020-08-20
美国5月9日最新疫情:美国确诊人数突破131万
 百态   2020-05-09
荷兰政府宣布将集体辞职
 干货   2020-04-30
倩女幽魂手游师徒任务情义春秋猜成语答案逍遥观:鹏程万里
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案神机营:射石饮羽
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案昆仑山:拔刀相助
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案天工阁:鬼斧神工
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案丝路古道:单枪匹马
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:与虎谋皮
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:李代桃僵
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:指鹿为马
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案金陵:小鸟依人
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案金陵:千金买邻
 干货   2019-11-12
 
推荐阅读
 
 
 
>>返回首頁<<
 
靜靜地坐在廢墟上,四周的荒凉一望無際,忽然覺得,淒涼也很美
© 2005- 王朝網路 版權所有