2008年8月29日星期五

续上一篇---UltraEdit 对UTF-8文件的自动处理

长期的疑问,太过信赖ultraedit。。。
http://www.aiview.com/2007/02/ultraedit_auto_detect_utf-8_file.html

关于Unicode 编码,这里有篇文章 可以参考。Unicode是几种多字节编码格式的统称,其中使用广泛的有UTF-8与UTF-16,而通常人们说Unicode时,实际是在指UTF-16编码,UltraEdit 就是这样,为了避免混淆,下面都按照标准引用名字。

使用UltraEdit 打开一个UTF-8 编码的文件,然后按ctrl+h 进入16进制模式查看文件内码,你会发现文件已经被转换成UTF-16 编码,并添加了UTF-16 little endian 的BOM :FF FE,UltraEdit 状态栏文件的尺寸也增加了不少。其实大可不必担心,可以回到正常模式继续编辑并保存,保存后的文件并没有改变编码格式,只是在编辑时使用UTF-16格式而已。

因此,如果通过UltraEdit打开文件查看BOM 来确定文件格式,并不是安全的。UltraEdit 下方状态栏则真实的显示了当前打开文件的实际编码格式,而不是当前编辑的编码格式。 对于一个普通Ascii 格式的文件,它显示为DOS 或者UNIX,对于一个包含有UTF-8编码字符的文件,它显示为U8-DOS 或者U8-UNIX,对于UTF-16编码的文件,它显示为U-DOS 或者U-UNIX。

我们知道,UTF-8 对于Ascii 字符的编码与原有的Ascii 编码一致,因此假如我们删除了一个UTF-8 DOS文件中所有Ascii 以外的字符,保存后再打开,UltraEdit 将显示为DOS(Ascii)。

如果我们不希望UltraEdit 在打开UTF-8 文件时自动转为UTF-16 格式编辑,我们可以修改配置。如下图,确保“自动检测 UTF-8文件”不被选中。

UltraEdit configuration

需要注意的是,如果取消了这个选项,UltraEdit打开包含UTF-8编码的文件会产生乱码。

UltraEdit 在File-Convertions 菜单中提供了多种编码格式之间的转换,这将影响到保存的文件编码,转换后,在状态栏也能看到相应变化。在有些选项后标明有(Unicode Editing) 或者(ASCII Editing),这指定了编辑时显示用的编码,并不影响保存文件所用的编码,要区分开。

工具WinHex 可以用来查看文件16进制内码。

字符编码笔记:ASCII,Unicode和UTF-8

今天中午,我突然想搞清楚UnicodeUTF-8之间的关系,于是就开始在网上查资料。

字符编码笔记:ASCII,UnicodeUTF-8


今天中午,我突然想搞清楚UnicodeUTF-8之间的关系,于是就开始在网上查资料。

结果,这个问题比我想象的复杂,从午饭后一直看到晚上9点,才算初步搞清楚。

下面就是我的笔记,主要用来整理自己的思路。但是,我尽量试图写得通俗易懂,希望能对其他朋友有用。毕竟,字符编码是计算机技术的基石,想要熟练使用计算机,就必须懂得一点字符编码的知识。

1. ASCII码

我们知道,在计算机内部,所有的信息最终都表示为一个二进制的字符串。每一个二进制位(bit)有0和1两种状态,因此八个二进制位就可以组合出 256种状态,这被称为一个字节(byte)。也就是说,一个字节一共可以用来表示256种不同的状态,每一个状态对应一个符号,就是256个符号,从 0000000到11111111。

上个世纪60年代,美国制定了一套字符编码,对英语字符与二进制位之间的关系,做了统一规定。这被称为ASCII码,一直沿用至今。

ASCII码一共规定了128个字符的编码,比如空格“SPACE”是32(二进制00100000),大写的字母A是65(二进制01000001)。这128个符号(包括32个不能打印出来的控制符号),只占用了一个字节的后面7位,最前面的1位统一规定为0。

2、非ASCII编码

英语用128个符号编码就够了,但是用来表示其他语言,128个符号是不够的。比如,在法语中,字母上方有注音符号,它就无法用ASCII码表示。 于是,一些欧洲国家就决定,利用字节中闲置的最高位编入新的符号。比如,法语中的é的编码为130(二进制10000010)。这样一来,这些欧洲国家使 用的编码体系,可以表示最多256个符号。

但是,这里又出现了新的问题。不同的国家有不同的字母,因此,哪怕它们都使用256个符号的编码方式,代表的字母却不一样。比如,130在法语编码 中代表了é,在希伯来语编码中却代表了字母Gimel (ג),在俄语编码中又会代表另一个符号。但是不管怎样,所有这些编码方式中,0—127表示的符号是一样的,不一样的只是128—255的这一段。

至于亚洲国家的文字,使用的符号就更多了,汉字就多达10万左右。一个字节只能表示256种符号,肯定是不够的,就必须使用多个字节表达一个符号。 比如,简体中文常见的编码方式是GB2312,使用两个字节表示一个汉字,所以理论上最多可以表示256x256=65536个符号。

中文编码的问题需要专文讨论,这篇笔记不涉及。这里只指出,虽然都是用多个字节表示一个符号,但是GB类的汉字编码与后文的UnicodeUTF-8是毫无关系的。

3.Unicode

正如上一节所说,世界上存在着多种编码方式,同一个二进制数字可以被解释成不同的符号。因此,要想打开一个文本文件,就必须知道它的编码方式,否则用错误的编码方式解读,就会出现乱码。为什么电子邮件常常出现乱码?就是因为发信人和收信人使用的编码方式不一样。

可以想象,如果有一种编码,将世界上所有的符号都纳入其中。每一个符号都给予一个独一无二的编码,那么乱码问题就会消失。这就是Unicode,就像它的名字都表示的,这是一种所有符号的编码。

Unicode当然是一个很大的集合,现在的规模可以容纳100多万个符号。每个符号的编码都不一样,比如,U+0639表示阿拉伯字母Ain,U+0041表示英语的大写字母A,U+4E25表示汉字“严”。具体的符号对应表,可以查询unicode.org,或者专门的汉字对应表

4. Unicode的问题

需要注意的是,Unicode只是一个符号集,它只规定了符号的二进制代码,却没有规定这个二进制代码应该如何存储。

比如,汉字“严”的unicode是十六进制数4E25,转换成二进制数足足有15位(100111000100101),也就是说这个符号的表示至少需要2个字节。表示其他更大的符号,可能需要3个字节或者4个字节,甚至更多。

这里就有两个严重的问题,第一个问题是,如何才能区别unicode和ascii?计算机怎么知道三个字节表示一个符号,而不是分别表示三个符号呢?第二个问题是,我们已经知道,英文字母只用一个字节表示就够了,如果unicode统一规定,每个符号用三个或四个字节表示,那么每个英文字母前都必然有二到三个字节是0,这对于存储来说是极大的浪费,文本文件的大小会因此大出二三倍,这是无法接受的。

它们造成的结果是:1)出现了unicode的多种存储方式,也就是说有许多种不同的二进制格式,可以用来表示unicode。2)unicode在很长一段时间内无法推广,直到互联网的出现。

5.UTF-8

互联网的普及,强烈要求出现一种统一的编码方式。UTF-8就是在互联网上使用最广的一种unicode的实现方式。其他实现方式还包括UTF-16和UTF-32,不过在互联网上基本不用。重复一遍,这里的关系是,UTF-8Unicode的实现方式之一。

UTF-8最大的一个特点,就是它是一种变长的编码方式。它可以使用1~4个字节表示一个符号,根据不同的符号而变化字节长度。

UTF-8的编码规则很简单,只有二条:

1)对于单字节的符号,字节的第一位设为0,后面7位为这个符号的unicode码。因此对于英语字母,UTF-8编码和ASCII码是相同的。

2)对于n字节的符号(n>1),第一个字节的前n位都设为1,第n+1位设为0,后面字节的前两位一律设为10。剩下的没有提及的二进制位,全部为这个符号的unicode码。

下表总结了编码规则,字母x表示可用编码的位。

Unicode符号范围 | UTF-8编码方式
(十六进制) | (二进制)
--------------------+---------------------------------------------
0000 0000-0000 007F | 0xxxxxxx
0000 0080-0000 07FF | 110xxxxx 10xxxxxx
0000 0800-0000 FFFF | 1110xxxx 10xxxxxx 10xxxxxx
0001 0000-0010 FFFF | 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx

下面,还是以汉字“严”为例,演示如何实现UTF-8编码。

已知“严”的unicode是4E25(100111000100101),根据上表,可以发现4E25处在第三行的范围内(0000 0800-0000 FFFF),因此“严”的UTF-8编码需要三个字节,即格式是“1110xxxx 10xxxxxx 10xxxxxx”。然后,从“严”的最后一个二进制位开始,依次从后向前填入格式中的x,多出的位补0。这样就得到了,“严”的UTF-8编码是“11100100 10111000 10100101”,转换成十六进制就是E4B8A5。

6. UnicodeUTF-8之间的转换

通过上一节的例子,可以看到“严”的Unicode码是4E25,UTF-8编码是E4B8A5,两者是不一样的。它们之间的转换可以通过程序实现。

在Windows平台下,有一个最简单的转化方法,就是使用内置的记事本小程序Notepad.exe。打开文件后,点击“文件”菜单中的“另存为”命令,会跳出一个对话框,在最底部有一个“编码”的下拉条。

bg2007102801.jpg

里面有四个选项:ANSI,UnicodeUnicode big endian 和 UTF-8

1)ANSI是默认的编码方式。对于英文文件是ASCII编码,对于简体中文文件是GB2312编码(只针对Windows简体中文版,如果是繁体中文版会采用Big5码)。

2)Unicode编码指的是UCS-2编码方式,即直接用两个字节存入字符的Unicode码。这个选项用的little endian格式。

3)Unicode big endian编码与上一个选项相对应。我在下一节会解释little endian和big endian的涵义。

4)UTF-8编码,也就是上一节谈到的编码方法。

选择完”编码方式“后,点击”保存“按钮,文件的编码方式就立刻转换好了。

7. Little endian和Big endian

上一节已经提到,Unicode码可以采用UCS-2格式直接存储。以汉字”严“为例,Unicode码是4E25,需要用两个字节存储,一个字节是4E,另一个字节是25。存储的时候,4E在前,25在后,就是Big endian方式;25在前,4E在后,就是Little endian方式。

这两个古怪的名称来自英国作家斯威夫特的《格列佛游记》。在该书中,小人国里爆发了内战,战争起因是人们争论,吃鸡蛋时究竟是从大头(Big- Endian)敲开还是从小头(Little-Endian)敲开。为了这件事情,前后爆发了六次战争,一个皇帝送了命,另一个皇帝丢了王位。

因此,第一个字节在前,就是”大头方式“(Big endian),第二个字节在前就是”小头方式“(Little endian)。

那么很自然的,就会出现一个问题:计算机怎么知道某一个文件到底采用哪一种方式编码?

Unicode规范中定义,每一个文件的最前面分别加入一个表示编码顺序的字符,这个字符的名字叫做”零宽度非换行空格“(ZERO WIDTH NO-BREAK SPACE),用FEFF表示。这正好是两个字节,而且FF比FE大1。

如果一个文本文件的头两个字节是FE FF,就表示该文件采用大头方式;如果头两个字节是FF FE,就表示该文件采用小头方式。

8. 实例

下面,举一个实例。

打开”记事本“程序Notepad.exe,新建一个文本文件,内容就是一个”严“字,依次采用ANSI,UnicodeUnicode big endian 和 UTF-8编码方式保存。

然后,用文本编辑软件UltraEdit中的”十六进制功能“,观察该文件的内部编码方式。

1)ANSI:文件的编码就是两个字节“D1 CF”,这正是“严”的GB2312编码,这也暗示GB2312是采用大头方式存储的。

2)Unicode:编码是四个字节“FF FE 25 4E”,其中“FF FE”表明是小头方式存储,真正的编码是4E25。

3)Unicode big endian:编码是四个字节“FE FF 4E 25”,其中“FE FF”表明是大头方式存储。

4)UTF-8:编码是六个字节“EF BB BF E4 B8 A5”,前三个字节“EF BB BF”表示这是UTF-8编码,后三个“E4B8A5”就是“严”的具体编码,它的存储顺序与编码顺序是一致的。

9. 延伸阅读

* The Absolute Minimum Every Software Developer Absolutely, Positively Must Know About Unicode and Character Sets(关于字符集的最基本知识)

* 谈谈Unicode编码

* RFC3629:UTF-8, a transformation format of ISO 10646(如果实现UTF-8的规定)

(完)

相关内容

随机文章

  • 2006.05.15: 《日瓦戈医生》的结尾(Doctor Zhivago)
    晚上,我躺在床上看书,突然读到这样一段:“至今我还记得大卫·里恩的电影《日瓦戈医生》结尾。医生说日瓦戈的心脏已经脆若薄纸。有一天他在莫斯科,坐在 巴士上,车过街角,看到一个年轻女人在路边走,以为那是心爱的拉拉。他挣扎着下车。病犯了,气喘不过来,他松开领带,跌跌撞撞的走到人行道上,只走了两 步,载倒在地上,就这样死了。死亡追逐爱情,爱情正是我们以死相求的东西。”
  • 2007.04.26: 2007年普利策奖回顾之二:突发新闻奖
    突发新闻奖(BREAKING NEWS REPORTING) 2006年11月17日,星期五 35岁的James Kim带着妻子和两个女儿——一个4岁,另一个7个月——离开旧金山,开车前往西雅图的叔叔家,一起过感恩节假期。他是一个网站编辑。

功能链接

广告(点击支持我)



评论

Stark 说:

很有意思的内容
讲解得通俗易懂,非常感谢您用较长的时间学习,并用精简的语言概括

flyisland 说:

本人是计算机从业人员,对文中提到的知识也都基本了解,但是像阮兄这样,花了半天时间就弄清楚来龙去脉,同时讲述的如此清楚,实在佩服。

本帖有pmp嫌疑,但实在是不能不p啊 :)。我想,动手写过技术文章的人都会同意我的。

只如初见 说:

是啊,我这个超级菜鸟都看明白了,阮兄对技术的理解和说明能力叫人佩服,谢谢分享。

姬着 说:

文章里说:UCS-2编码方式,即直接用两个字节存入字符的Unicode码。

那USC-2编码方式如何实现超过两个字节的符号的存储?谢谢

大徐 说:

对了解字符编码很有帮助,谢谢!

Ruan YiFeng 说:

引用只如初见的发言:
是啊,我这个超级菜鸟都看明白了,阮兄对技术的理解和说明能力叫人佩服,谢谢分享。

“延伸阅读”中第一个链接,才是真正的通俗易懂,我只是向他学习而已。

Ruan YiFeng 说:

引用姬着的发言:
文章里说:UCS-2编码方式,即直接用两个字节存入字符的Unicode码。 那USC-2编码方式如何实现超过两个字节的符号的存储?谢谢

USC-2只能用存储两个字节的Unicode,超过这一范围的符号,它不能表示。

Annis 说:


我是Annis,想邀请您参加拼搏到底FeedSky博客挑战赛,
这是一个很好的宣传、展示自己的机会,
有兴趣您可以自己到相关网站了解具体参赛细节。
http://www.feedsky.com/challenge/?u=141270

Bill 说:

PS:本文只是主要介绍了UTF-8编码,下面这篇文章对于GB码与Big5有更详细的介绍。

汉字编码中现在主要用到的有三类,包括GBK,GB2312和Big5。

1、GB2312又称国标码,由国家标准总局发布,1981年5月1日实施,通行于大陆。新加坡等地也使用此编码。它是一个简化字的编码规范,当然也包括 其他的符号、字母、日文假名等,共7445个图形字符,其中汉字占6763个。我们平时说6768个汉字,实际上里边有5个编码为空白,所以总共有 6763个汉字。

GB2312规定“对任意一个图形字符都采用两个字节表示,每个字节均采用七位编码表示”,习惯上称第一个字节为“高字节”,第二个字节为“低字节”。 GB2312中汉字的编码范围为,第一字节0xB0-0xF7(对应十进制为176-247),第二个字节0xA0-0xFE(对应十进制为160- 254)。

GB2312将代码表分为94个区,对应第一字节(0xa1-0xfe);每个区94个位(0xa1-0xfe),对应第二字节,两个字节的值分别为区号 值和位号值加32(2OH),因此也称为区位码。01-09区为符号、数字区,16-87区为汉字区(0xb0-0xf7),10-15区、88-94区 是有待进一步标准化的空白区。


2、Big5又称大五码,主要为香港与台湾使用,即是一个繁体字编码。每个汉字由两个字节构成,第一个字节的范围从0X81-0XFE(即129- 255),共126种。第二个字节的范围不连续,分别为0X40-0X7E(即64-126),0XA1-0XFE(即161-254),共157种。


3、GBK是GB2312的扩展,是向上兼容的,因此GB2312中的汉字的编码与GBK中汉字的相同。另外,GBK中还包含繁体字的编码,它与Big5 编码之间的关系我还没有弄明白,好像是不一致的。GBK中每个汉字仍然包含两个字节,第一个字节的范围是0x81-0xFE(即129-254),第二个 字节的范围是0x40-0xFE(即64-254)。GBK中有码位23940个,包含汉字21003个。

Bill再推荐一个网站 专门介绍汉字与汉字计算机化的 汉典 http://www.zdic.net/

简单 说:

http://www.zdic.net/


很强的网站,收藏

Ruan YiFeng 说:

引用Bill的发言:
本文只是主要介绍了UTF-8编码,下面这篇文章对于GB码与Big5有更详细的介绍。

这篇网志中有两个地方需要补充一下,我忘了在原文中提到。

1.

国际标准化组织通过了一套ISO-8859-1的编码,规定了单字节256个符号的编码方式。目前,这是8位编码的国际标准。

2.

Unicode编码中表示字节排列顺序的那个文件头,叫做BOM(byte-order mark),FFFE和FEFF就是不同的BOM。

UTF-8文件的BOM是“EF BB BF”,但是UTF-8的字节顺序是不变的,因此这个文件头实际上不起作用。有一些编程语言是ISO-8859-1编码,所以如果用UTF-8针对这些语言编程序,就必须去掉BOM,即保存成“UTF-8—无BOM”的格式才可以,PHP语言就是这样。

请教 说:

我怎么用 notepad 保存成 UTF-8
用 UltraEdit 看 还是 FF FE 25 4E啊???

请教 说:

引用请教的发言:
我怎么用 notepad 保存成 UTF-8 后 用 UltraEdit 看 还是 FF FE 25 4E啊???
哦 知道了。 是UltraEdit 默认会以 UTF-16的方式打开UTF-8编码的文件, 要设置或者用Hex Workshop打开就可以看到楼主所说的效果。

Cloudream 说:

(点击支持我)

这些字符是违反adsense规定的……

jackywdx 说:

这么精彩的讲解,实在不得不向作者致敬!
内容讲解得非常详细但又通俗易懂,谢谢了~~

jinwangen 说:

非常感谢

LMN 说:

非常感谢,值得一看

网友 说:

标题“6. UnicodeUTF-8之间的转换”不严谨。

Unicode是一种字符集,概念比较抽象,你已经提到,它存储的时候必须用适当的编码方式。

你的标题的意思,实际上是UTF-16和UTF-8之间的转换。

至于windows notepad保存对话框的编码方式列表中列出“Unicode”这一个名字,实际上是一个通俗的称呼(来自windows NT的早期版本的习惯,一直沿用),指UTF-16,而不是严格的称呼。希望你行文不要受这个影响。

Ruan YiFeng 说:

引用网友的发言:

标题“6. UnicodeUTF-8之间的转换”不严谨。

Unicode是一种字符集,概念比较抽象,你已经提到,它存储的时候必须用适当的编码方式。

你的标题的意思,实际上是UTF-16和UTF-8之间的转换。

UTF-16不等于unicode啊,不能混为一谈。

Ivan WONG 说:

嗯,看完了長不少知識.

Michael Zheng 说:

我只能这么说,看了那么多的对字符集的解释

这个绝对是最通俗易懂并且还解决了常见疑问的最好的文章 :)

收藏

wxs8088 说:

很好的一编文章

人跟人的差距咋就这么大呢 说:

好文章!收藏了!

楼主何不把ansi编码方式也说说!
让俺这样的小学新生借楼主的理解能力再学习一把.

学习了 说:

学习了

水中鱼 说:

引用Ruan YiFeng的发言:

UTF-16不等于unicode啊,不能混为一谈。


UTF-16扩充了Unicode,包括了一些稀有字符,想我们国家的满文,藏文等等,两者基本上等价

heroboy 说:

其实我认为,编码其实有2个意思。1.一个是把字符和数字对应起来(比如unicode和GBXXXX等)。2.还有就是相应在数字在计算机中的表示,也就是和字节序列对应起来(比如utf8,mbcs等)。
我有个问题,windows下的mbcs编码(2)用的编码(1)是不是GB系列的编码(1),而unicode编码(2)用的是unicode编码(1)

Demo 说:

拜读。。。受益匪浅。。长见识了 。。顶楼主

2008年08月15日 01:56 | | 引用

2008年8月27日星期三

multi-office

"C:\Program Files\Microsoft Office\Office11\Excel.exe" /regserver

2008年8月21日星期四

http://www.perl.com/pub/a/2003/11/21/slurp.html
Both of those slurps used localized filehandles to be compatible with 5.005. Here they are with 5.6.0 lexical autovivified handles:
{
local( $/ ) ;
open( my $fh, $file ) or die "sudden flaming death\n"
$text = <$fh>
}
open( my $fh, $file ) or die "sudden flaming death\n"
my $text = do { local( $/ ) ; <$fh> } ;
And this is a variant of that idiom that removes the need for the open call:
my $text = do { local( @ARGV, $/ ) = $file ; <> } ;
The filename in $file is assigned to a localized @ARGV and the null filehandle is used which reads the data from the files in @ARGV.
Instead of assigning to a scalar, all the above slurps can assign to an array and it will get the file but split into lines (using $/ as the end of line marker).
There is one common variant of those slurps which is very slow and not good code. You see it around, and it is almost always cargo cult code:

2008年8月13日星期三

perl modules

http://www.bribes.org/perl/ppmdir.html

ActivePerl模块手动安装

ActivePerl模块手动安装
http://ppm.activestate.com/PPMPackages/zips/

ActivePerl是Windows下最常用的Perl版本,它使用一个名为ppm的工具来管理模块。 安装Perl模块最简单的方法就是利用 ppm,search之后再install。但由于某些原因(比如ppm不能上网)导致不能直接 使用ppm安装模块时,可以利用下面的方法。

用浏览器打开ActiveState的Perl模块发布站, 然后选择相应的版本(一般是选择8xx的Windows目录)。注意模块列表页面比较大,须耐心等待。 模块列表打开后选择自己需要的zip包下载,例如我下载了 DBD-Oracle-1.17.zip。

下载之后将其解压到C:\下(不一定是C盘,但一定要解压到根目录下),出现两个文件:DBD-Oracle-1.17.tar.gz和 DBD-Oracle-1.17.ppd。然后打开命令行,切换路径到到 C:\,然后输入 ppm-shell 启动 ppm,输入以下命令即可安装。

install C:\DBD-Oracle-1.17.ppd

perl中调用C函数的一个例子(XS方式)

背景:因为一个临时的工作需要,花了一天的时间写了一个小程序,在perl中调用C函数(用的是XS方式),记录如下。这个程序实现了一个定制的CRC32计算(perl的Digest::CRC有一般的CRC计算,但不适用于我的应用)。
前提:
1. 安装了ActivePerl 5.8
2. 安装了VC或Dev-C++,正确设置了环境变量

操作过程如下:
1. 在命令行下执行
> h2xs -A wldemo
> cd wldemo
2. 编辑文件wldemo.xs, wldemo.xs修改后的内容如下:
/*
CCITT crc32 perl XS implementation.
Author: Wang Lei
Create Date: Jan 30, 2008

Usage:
use WLDEMO;
my @data = (0x00, 0x00, 0x00, 0x00);
WLDEMO->crc32_init();
printf("%x", WLDEMO->crc32(4, pack("C4", @data)));
*/
#include "EXTERN.h"
#include "perl.h"
#include "XSUB.h"
#include "ppport.h"

#define CRCPOLY 0xEDB88320UL
#define CRCINIT 0xFFFFFFFF
unsigned long c_dCrcTable32[UCHAR_MAX + 1];


MODULE = WLDEMO PACKAGE = WLDEMO

void
crc32_init(char *classname)
CODE:
unsigned int i, j;
unsigned long r;

for (i = 0; i <= UCHAR_MAX; i++)
{
r = i;
for (j = 0; j < CHAR_BIT; j++)
{
if (r & 1)
{
r = (r >> 1) ^ CRCPOLY;
}
else
{
r >>= 1;
}
}
c_dCrcTable32[i] = r;
}


unsigned long
crc32(char *classname, int n, char* c)
CODE:
unsigned long r;
unsigned char* p = (unsigned char*)c;

r = CRCINIT;
while (--n >= 0)
{
r = (r >> CHAR_BIT) ^ c_dCrcTable32[(unsigned char)r ^ (*p)];
p++;
}

r = ~r;
RETVAL = r;
OUTPUT:
RETVAL


3. 在命令行下执行
> perl Makefile.PL
4. 编辑文件makefile,将obj替换为o (因为我使用的是gcc,如果是VC, 则不需要修改)
5. 在命令行下执行
> nmake
> nmake install
6. 测试, 测试程序如下:
use WLDEMO;

my @data1 = (0x00, 0x00, 0x00, 0x00);
my @data2 = (0xFF, 0xFF, 0xFF, 0xFF);
my @data3 = (0x01, 0x02, 0x03, 0x04);
my @data4 = (0x04, 0x03, 0x02, 0x01);
my @data5 = (0x00, 0x00, 0x00);
my @data6 = (0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF);

WLDEMO->crc32_init();

printf("%x\n", WLDEMO->crc32(4, pack("C4", @data1)));
printf("%x\n", WLDEMO->crc32(4, pack("C4", @data2)));
printf("%x\n", WLDEMO->crc32(4, pack("C4", @data3)));
printf("%x\n", WLDEMO->crc32(4, pack("C4", @data4)));
printf("%x\n", WLDEMO->crc32(3, pack("C3", @data5)));
printf("%x\n", WLDEMO->crc32(5, pack("C5", @data6)));

经验:perl给C函数的参数,如果是标量比较简单,一般不需要修改;如果C函数的参数是指针,则不能直接把数组的引用传进去,应该用pack转换为字符串然后传进去。我刚开始没有用pack函数,结果计算的值一直不变。
参考资料:
http://search.cpan.org/~fayland/POD2-CN-0.02/

2008年8月10日星期日

正则表达式中的模式修正符

下面列出了当前在 PCRE 中可能使用的修正符。括号中是这些修正符的内部 PCRE 名。修正符中的空格和换行被忽略,其它字符会导致错误。


i (PCRE_CASELESS)
如果设定此修正符,模式中的字符将同时匹配大小写字母。
m(PCRE_MULTILINE)
默 认情况下,PCRE 将目标字符串作为单一的一“行”字符所组成的(甚至其中包含有换行符也是如此)。“行起始”元字符(^)仅仅匹配字符串的起始,“行结束”元字符($)仅 仅匹配字符串的结束,或者最后一个字符是换行符时其前面(除非设定了 D 修正符)。这和 Perl 是一样的。 当设定了此修正符,“行起始”和“行结束”除了匹配整个字符串开头和结束外,还分别匹配其中的换行符的之后和之前。这和 Perl 的 /m 修正符是等效的。如果目标字符串中没有“\n”字符或者模式中没有 ^ 或 $,则设定此修正符没有任何效果。
s(PCRE_DOTALL)
如果设定了此修正符,模式中的圆点元字符(.)匹配所有的字符,包括换行符。没有此设定的话,则不包括换行符。这和 Perl 的 /s 修正符是等效的。排除字符类例如 [^a] 总是匹配换行符的,无论是否设定了此修正符。
x(PCRE_EXTENDED)
如 果设定了此修正符,模式中的空白字符除了被转义的或在字符类中的以外完全被忽略,在未转义的字符类之外的 # 以及下一个换行符之间的所有字符,包括两头,也都被忽略。这和 Perl 的 /x 修正符是等效的,使得可以在复杂的模式中加入注释。然而注意,这仅适用于数据字符。空白字符可能永远不会出现于模式中的特殊字符序列,例如引入条件子模式 的序列 (?( 中间。
e
如果设定了此修正符,preg_replace() 在替换字符串中对逆向引用作正常的替换,将其作为 PHP 代码求值,并用其结果来替换所搜索的字符串。
只有 preg_replace() 使用此修正符,其它 PCRE 函数将忽略之。

Note: 本修正符在 PHP3 中不可用。


A(PCRE_ANCHORED)
如果设定了此修正符,模式被强制为“anchored”,即强制仅从目标字符串的开头开始匹配。此效果也可以通过适当的模式本身来实现(在 Perl 中实现的唯一方法)。
D(PCRE_DOLLAR_ENDONLY)
如果设定了此修正符,模式中的美元元字符仅匹配目标字符串的结尾。没有此选项时,如果最后一个字符是换行符的话,美元符号也会匹配此字符之前(但不会匹配任何其它换行符之前)。如果设定了 m 修正符则忽略此选项。Perl 中没有与其等价的修正符。
S
当一个模式将被使用若干次时,为加速匹配起见值得先对其进行分析。如果设定了此修正符则会进行额外的分析。目前,分析一个模式仅对没有单一固定起始字符的 non-anchored 模式有用。
U(PCRE_UNGREEDY)
本修正符反转了匹配数量的值使其不是默认的重复,而变成在后面跟上“?”才变得重复。这和 Perl 不兼容。也可以通过在模式之中设定 (?U) 修正符或者在数量符之后跟一个问号(如 .*?)来启用此选项。
X(PCRE_EXTRA)
此 修正符启用了一个 PCRE 中与 Perl 不兼容的额外功能。模式中的任何反斜线后面跟上一个没有特殊意义的字母导致一个错误,从而保留此组合以备将来扩充。默认情况下,和 Perl 一样,一个反斜线后面跟一个没有特殊意义的字母被当成该字母本身。当前没有其它特性受此修正符控制。
u(PCRE_UTF8)
此 修正符启用了一个 PCRE 中与 Perl 不兼容的额外功能。模式字符串被当成 UTF-8。本修正符在 Unix 下自 PHP 4.1.0 起可用,在 win32 下自 PHP 4.2.3 起可用。自 PHP 4.3.5 起开始检查模式的 UTF-8 合法性。

来源 http://cn.php.net/manual/zh/reference.pcre.pattern.modifiers.php

2008年8月8日星期五

用Devel::SmallProf测量Perl函数的执行时间

http://tech.idv2.com/2006/10/03/perl-benchmark-by-devel-smallprof/

Devel::SmallProf 是个很好用的模块,可以方便地测量出代码每一行的执行时间,以便进一步优化。

例如以下程序,文件名为 prof_sample.pl。

#!/usr/bin/perl
my $str = "0";
for (my $i = 0; $i < 100; $i++) {
$str =~ s/\d+/($&+1)/e;
print $str."\n";
}

该程序的功能是输出整数 1 到 100。当然实际写程序时可不要用这么低效率的方法。 安装 Devel::SmallProf 之后我们来测量一下它每一行代码的执行时间。

perl -d:SmallProf prof_sample.pl

执行之后会在当前目录下生成一个 smallprof.out 文件,其内容如下:

           ================ SmallProf version 1.15 ================
Profile of prof_sample.pl Page 1
=================================================================
count wall tm cpu time line
0 0.000000 0.000000 1:#!/usr/bin/perl
0 0.000000 0.000000 2:
1 0.000006 0.000000 3:my $str = "0";
101 0.006418 0.010000 4:for (my $i = 0; $i < 100; $i++) {
200 0.002581 0.000000 5: $str =~ s/\d+/($&+1)/e;
100 0.001509 0.000000 6: print $str."\n";
1 0.000003 0.000000 7:}

前三列的数字分别为执行次数、消耗时间、消耗CPU时间。

如果你的程序使用 use 语句引用了其他模块,那么所有被引用的程序都将被分析,生成一个长长的报告。这时可以使用下面的命令来迅速找到耗时最长的命令。

sort -k 2nr,2 smallprof.out | less

2008年8月6日星期三

转-perl local my our 的前世今生

erl中的变量作用范围 local, my, our与全局变量

很古老很古老以前......嗯,不用老到白垩纪,那时候的Perl是自由射击的。没有什么定义变量的说法,所有的变量都是全局变量,也不需要任何 定义就可以使用。后来就出现了local, 再后来出现了use strict 'vars'和my, 再后来又有了our......所以今天的Perl大陆就有了崇山巨岭,一些变量就被限制在盆地里,老死于桃花源中。

因为要使用一个跨模块全局变量,研究了一下Perl的变量作用范围,写一点笔记吧。

1. 首先说our, 这个最晚出现但其实质却最早出现的变量修饰符。众所周知,在Perl不使用use strict 'vars'的时候,你可以任意使用变量而不需要实现定义:

$szStateMachineStatus = undef;

这行代码在使用了use strict 'vars'以后是编译不能通过的。如果这个变量是一个全局变量,那么可以定义

our $szStateMachineStatus = undef;

这个效果和在不使用use strict 'vars'时一样。"一样"意味着什么呢?

our $szStateMachineStatus = 'init';
{
$szStateMachineStatus = 'inited';
print $szStateMachineStatus;
}
print $szStateMachineStatus;

打印的结果是两个'inited'。顺便说,用our定义过的变量,可以在任何地方被再次用our定义,仍然和第一个our定义的变量是同一个。

2. my

慢慢地有人觉得Perl的"自由射击式"变量定义法则不行,最突出的就是一些常会打错字(typo)的人。假如你定义了一个变量叫$ szStateMachineStatus,可是在某个地方写成了$szStatMachineStatus,少了一个e。因为不use strict啊,所以没有任何警告,可以这样用。结果就是出了错你就慢慢debug去吧,很浪费时间,不符合Perl的懒惰文化。

然后就有了use strict 'vars'和my。有了use strict 'vars'以后,所有的变量在使用前必须先被定义。my的法则很简单,只在当前作用域起作用。比如说定义了
my $szStateMachineStatus;
那么如果是在文件头定义的,作用范围就到文件尾,在子函数里也能用。如果是在子函数里定义的,那么作用范围就只到函数结束。试看以下代码
foreach my $szName (@arrName){
print $szName;
}
在这个循环里Perl每次都创建一个新的$szName变量。换句话说,"my"是属于"见到my就新建"的变量。

3. local

其实这个定义都可以取消了。它是在my还没出现之前的一个权宜方案。比如说一个变量$i被定义成了全局变量,可是你又想暂时使用一个也叫$i的临时变量。
no strict 'vars';
$i = 9999;
{
local $i = 7777;
print "$i\n";
}
print "$i\n";
结果是7777, 9999。在出了local的作用域以后$i又回到了原来的值。在出现了my以后,没有任何理由需要使用local了,请忘记掉它吧。

4. 最后一个话题,全局变量

当你只有一个pl文件时,很简单,把你的全局变量在文件头部定义成our就行。可能你会看到有些书上说要使用use vars qw( $szVersion $szToolName); 这样的方式来把 $szVersion和$szToolName定义成全局变量。 注意了,use vars的用法是在my出现后,our出现之前的一个历史的盲肠。our的语法更自然,更易于理解,为什么不用our呢? --另外,在文件头把变量定义成my, 也是全局可用的,但是冒了风险,假如在某个函数里用my再定义一次,原来的值可就消失了。用our就不存在多次定义会导致丢值的状况。

当你在写一个有一个pl文件,N个pm文件的系统时该如何呢?事实上Perl里的变量和函数名都有一个系统级的名字。比如说你在某pm文件的头上定义了包名和全局变量
package bagua;
our $east = 'wood';
那么在任何地方,任何pm和pl文件里都可以使用$bagua::east来访问这个变量。$bagua::east就被称为系统级名字。这也能回答一个问题,为什么不同的perl包里面定义的同名全局变量间不会冲突,因为它们都被限制在包的名字空间下面了。

如果你是在pl里定义全局变量,而且该文件没有定义package名字怎么办?Perl会生成一个缺省的package,名字叫"main"。所以如果你的pl文件是这样
our $szVersion = '1.0.1";
那么在其它文件里就可以用$main::szVersion来访问,并不需要你定义package main.
最后,说一个邪门招式。你可以试一下定义任意一个含有::的变量
our $gColor::Blue = '0x0000FF';
这个变量就在任何地方可用,哪怕你从来没有定义过gColor这个package。这个是Perl的灵活性的体现,它看到这个就自动生成了gColor这个名字空间。当然,我不鼓励这种无厘头的用法。

2008年8月5日星期二

searching for the lost time

when i was filling out my mensal effort report,i tried to

2008年8月1日星期五

some perl books on-line

enjoy it
http://www.unix.com.ua/orelly/perl/

How can I use modules from CPAN

How can I use modules from CPAN?

As of version 5.005, ActivePerl supports the MakeMaker utility. This allows you to install modules from CPAN, but requires you to have a make utility, such as nmake or dmake. Modules are generally distributed in gzipped tar files, such as Data-Dumper-2.08.tar.gz.

However, ActivePerl includes the Perl Package Manager (PPM), a utility that allows you to install modules, including modules that contain binary extensions. You should consider using PPM to install a module, as this greatly simplifies the management of modules.

Nevertheless, there are times when it is necessary to build a module from source. Typically, an installation session goes something like this:

  1. Extract the module. This creates a directory based on the name of the archive.

        gzip -d -c Data-Dumper-2.08.tar.gz | tar xvf -
  2. Change directory to the module's directory.

        cd Data-Dumper-2.08
  3. Consult the README file.

        more < README
  4. Run the Makefile.PL script. This uses the MakeMaker module to build a makefile you can build the extension with.

        perl Makefile.PL
  5. Run your make utility. This prepares the module for installation, and compiles any extension if one is present.

        nmake
  6. If this module has tests, run them.

        nmake test
  7. If the tests succeeded, install the module.

        nmake install

See Where can I find Win32 ports of UNIX tools? for information on the availability of tools like gzip and tar.

http://aspn.activestate.com/ASPN/docs/ActivePerl/5.8/faq/Windows/ActivePerl-Winfaq9.html#How_can_I_use_modules_from_CPAN_