论坛: 编程破解 标题: 吸引C和Java程序员目光的Perl5.6 复制本贴地址    
作者: NetDemon [netdemon]    ADMIN   登录
Teodor Zlatanov
Programmer, Northern Light, Inc.
January 2001

笔者侧重于阐述 Perl 与 C 或 Java 不同的独特之处。您一定会为 Perl 这些在其他语言中看不到的特性而心花怒放:操作符的容错能力、一项任务多种实现、标点、正则表达式以及变量机制等。所有这些都赋予您的手指更灵活的魔力。在某些方面 Perl 的确能给 C 和 Java 程序员很多有用帮助,可惜目前它还远达不到众所周知的程度。因此,抓紧机会提高您的 Perl 水平吧!

Perl 有时甚至令有经验的程序员也觉得头疼,因为他们发现一不小心就会写出模棱两可的语句。但这种在结构、特性体系方面的模糊性从另一方面显示了 Perl 语言强大的能力。毕竟 Perl 语言最开始的设计初衷就是希望能用多种方式来达到同一目的。

这里我们将要探讨 Perl 5.6 中那些最容易混淆的特性,并将它们与 C/C++/Java 中相应的特性做比较。主要围绕 "Natural Language Principles in Perl" 中的原则展开(Larry Wall 著,参看本文末尾的 资料 部分),因为它们是 Perl 最能与 C、C++ 和 Java 语言区分开的地方。此外,关于 Perl 语法的结构可以在 "perldoc perlsyn" 参考文档中找到,另一本值得推荐的 Perl 指南读物则是 Programming Perl。(参看 资料 部分)

Perl 解释器
初学者马上就会发现 Perl 中似乎没有任何编译器。事实上,Perl 脚本大多是由 Perl 解释器直接运行的,例如 UNIX 系统下的 "Perl"、DOS/Windows 下的 "perl.exe" 就是 Perl 解释器。而在 MacOS 中则不需要这些解释器。您可以试试看如何运行 Perl 脚本。首先在您的操作系统上启动相应的 Perl 解释器,或是在 MacOS 系统中直接运行。在大多数系统中,文件尾标志(UNIX 系统中为 Control-D)用来表示用户输入结束。因此在 UNIX 系统中,下面这个脚本将能得到 "5+6" 的计算结果:

从最简单的 Perl 程序入手

> perl
(Perl is waiting for user input here, because no script name is given)
print 5+6
You press Control-D here
11  

 



可以看到 Perl 解释器运行了这个只有一行的脚本程序,并输入该表达式的计算结果 11。

Perl 解释器有许多选项。例如,-e 选项表示将命令行的输入作为脚本文件来执行,因此上面的脚本例子也可以这样实现:在命令行输入 perl -e'print 5+6'(注意,要用单引号将命令括起来)。而 -i 选项则类似于通过一个过滤器,允许在文件中不同的位置进行编辑。-n 和 -p 选项能让程序员打开或关闭输出。-w 选项与 C/C++ 中的 "-Wall" 编译选项类似,都能够对程序中潜在问题给出警告信息,但与 -Wall 不同的是,-w 功能在程序运行时也是被激活的。

速度和 Benchmark
人们常常拿 Perl 与 C/C++ 比较,并抱怨 Perl 运行速度不够快。某些时候这的确是事实,但是并非永远如此。我建议您在认为 C 或 C++ 更快之前,使用 Benchmark 模块试试看 (perldoc Benchmark)。此外,Perl 能很方便地与 C/C++ 代码或库连接,且某些 Perl 内置函数并不比 C 代码慢,如排序或打印等。这里再次提醒您在坚信 C/C++ 比较快之前,先使用一下 Benchmark 模块。

要记住,过早的优化往往是错误的根源。如果您在 Perl 中写了一个原型,并用其他语言来重写是没有问题的。原型意味着能够方便地开发。

与 Java 相比而言,Perl 也能够很好地工作。Perl 不象 Java 那样擅长于线程,但它的 Tk GUI 界面工具箱却比 Java 的 Swing GUI 库要好。并且 Java 代码总是能够连接到 Perl 程序中,反之亦然。因此,有时您可以通过某种程度上的结合,使得程序在两方面都做得很好。

异常、编译和文档
Perl 通过 CPAN 中的模块或是其内置函数 eval() 来抛出异常。就好像在 C++ 或 Java 中通过 try/catch 代码块来处理异常一样,eval 函数能处理某个代码段或某个字符串操作的异常。

事实上,Perl 程序在运行之前还是需要编译的,只是和 C/C++/Java 的编译方式不相同。在设计和效果上,它和 Java 的字节解释过程很相似。关于编译的更详尽内容,可以参阅 "perldoc perlrun" 和 "perldoc perlcc" 文档。

可用 POD 格式来将文档嵌入 Perl 程序。这种文档嵌入方式比 Javadoc 格式(仅适合于 API 文档)要通用,但比不上 C/C++/Java 的注释。

即使和 C、C++ 或 Java 比较起来,Perl 程序也不算是一种结构性强的语言。例如,BEGIN 语句块会被首先执行,但它可以在程序中多次说明。定义、变量和函数体可以在程序的任意位置出现,Perl 所提供地强大功能可以最好地满足这种随意性。

由于这种松散结构、嵌入的注释、以及为追求方便而导致的令人混淆的语句,使得书写 Perl 程序更像是在写一封英文信件。

Perl 的容错能力
Perl 比 C/C++/Java 更能容忍一些模糊地写法。例如可以用逗号来分隔语句或函数的参数:

语句之间或函数参数之间的分隔符

print 'Hello', ' ', 'there.', "\n";     # print "Hello there\n"

foreach (1..10)
{
 my $i;
 $i = $_ * 2, print "$i\n";             # print evens from 2 to 20


 



Perl 能尽最大可能地消除这些语句可能引起的歧义。当然,有些时候仍有无法解决的歧义(在这一点上,Perl 就象英语一样)。

Perl 中另一个容易引起歧义的地方在于:变量经常会被隐含使用。例如,"print" 语句缺省时会打印 $_ 变量的值。在其他一些含混的语句操作中,$_ 变量也是它们的缺省值,这就造成了一种混乱。例如:

隐含使用变量

$_ = "hello";
s/hello/hi/;                            # $_ is "hi" now
print;                                  # prints "hi"  

 



这里你可以看到,使用缺省变量能让编程方便简洁。也就是说,Perl 和英语类似,通过某种模糊性来简化表达式。

一项任务多种实现
(There's more than one way to do it ,TMTOWTDI)
所有的语言在解决问题时都有自己的方法。在 C 里面,for() 循环是在一定范围内重复的最好方法;在 Java 里,静态函数的调用是直接通过类而不是某个实例。

但对于同一件事情,Perl 至少有两种解决方法。TMTOWTDI 原则就是 Perl 的座右铭,各种处理上的差异在 Perl 编程中是深受鼓励的。

下面来看一个打印数组元素的例子。所有的表达方法都达到同一目的。

打印数组元素

print foreach @array;

foreach (@array) {print};

map {print} @array;

print @array;  

 



要理解以上这些代码的唯一途径就是掌握所有 Perl 的语法。不要担心哪种方法才是正确的,因为实现同一目标总是有多种正确的方法。考虑这些不同的表达方式,您可以更深刻体会 Perl 的这个座右铭。

另外,虽然一个任务的实现有多种方法,但这并不意味着所有方法都是正确的。通常情况下,更有可能写出的是一些错误代码。为了保证代码的正确性,最好尽量使用那些 Perl 内置的函数,而较少使用自己所编写的函数,并且注意证明并记录这些不那么显然的方法。

正则表达式
如果没有初始化,正则表达式很有可能造成一片混乱。大多数人都相信正则表达式是由 Kalahari bushmen 发明的,它渗透到了大学的计算机科学编程的所有方面。

Perl 的正则表达式是从 shell 脚本程序以及 awk/grep 工具中继承而来的。但它的能力却远远超出了原来的模型。

基础的正则表达式是非常容易书写的,但难以读懂。例如 "con\w+" 和 "contra"、"contrary" 匹配,但与 "pro" 或 "con" 都不匹配。然而在 Perl 5.6.0 中,正则表达式被固化了。Unicode 字符集、模式内任意代码操作、flag toggles、条件表达式以及其他特征都被添加到正则表达式库中。

对于初学者的一个最好的建议就是:首先学习最基本的正则表达式(参阅 资料 部分,或 "perldoc perlre" 参考手册),稍后才进一步学习那些复杂的高级特性。由于正则表达式必须全写在一起,中间没有办法添加注释,这就让它们成为所有 Perl 代码中最难读懂的一部分。因此建议大家书写已成型的代码。

在 C/C++/Java 中正则表达式属于外部的函数包,但 Perl 是目前最佳的正则表达式搜索和代换工具。在极少数情况下,它可能会比纯 C 程序慢一些,但对于那些纯粹面向正则表达式的问题,Perl 依然是您首选的工具。

标量、数组和哈希散列
和 C、C++、Java 中变量不同的是,Perl 的变量的类型是由其名字决定的,并且会自动初始化成相应类型。这一点让 Perl 初学者觉得很不习惯,但它非常地直观而易于理解。

笔者推荐使用 "use strict"。通过它可以保证变量在使用之前声明,从而避免打字错误等引起的程序错误。 


如果没有做到这一点,则有可能遇到下面这样的问题:

一个常见的打字错误

$i = 5;
print $j;                               # print $i 

 



此例子中,程序员本来要打印变量 i 的值,结果却敲成了 j。Perl 并不会觉得这段代码有什么问题,它会继续执行打印语句,显示 $j 的值即什么都没有。有些时候,Perl 的自动生成对象的确很有用,但以我的经验来说,最好还是用 "use strict" 来关掉这一自动功能,从而避免上述问题。

Perl 变量可以是标量 (scalars)、数组 (arrays)或哈希散列 (hashes,又叫做关联数组)。(事实上,Perl 中有多种数据类型,但是程序员并不会直接面对它们。)此外也可以是引用,通常它们也是一种标量类型。其中标量名称以 "$" 开头,数组名以 "@" 开头,而散列则以 "%" 开头。

标量是 Perl 中最简单的数据类型。每个标量都有唯一的值,或者是字符串或者是引用。在必要的时候,字符串和数字可以互相转化。这常让初学者觉得欣喜异常。看一下这个例子:

标量

$i = "hi there";
print 1+$i;                             # prints 1

 



其中标量 $i 的值是字符串 "hi there",它对应的数值为 0。因此 1 + "hi there" 的值为 1,程序运行结果为 1。

不过这并不意味着 Perl 解释器在对某个标量分别考虑其字符串类型和数字类型。事实上,在内存中只是一个含有某个值的标量。如果在数值运算的语句中(如加法),这个标量值就转化成数值形式;如果在字符串操作语句中(例如打印),则以字符串形式执行。但无论以什么形式运算,该标量变量实质上只有一个值。

未定义的标量的值为 "undef"。如果在 C/C++/Java 程序中,您可以将其他值与 null 比较,但在 Perl 中却不能拿任何东西来与 "undef" 做比较。可用这样使用 defined() 函数:

Use of the 'defined()' function

$i = "hi there";
print $i if defined $i;                 # prints "hi there"
undef $i;                               # set $i to be undef
print $i if defined $i;                 # prints nothing  

 



数组实质上就是一组标量。如果需要,数组大小可以自动改变,有点象 Java 中的 Vector 类。C 和 C++ 中没有与 Perl 数组类型相当的东西,但它们也有一些提供类似功能的库(如 STL)。数组的一个有趣特性在于,数组的标量数值等于它的元素个数:

数组中的元素个数

@a = ("hi there", "nowhere");
print scalar @a;                        # prints 2
push @a, "hello";                       # add "hello" at the end
print scalar @a;                        # prints 3  

 



散列与数组类似,但里面的标量并不是按照位置排序的,而是通过另一个标量(必须是唯一值)来进行索引。例如一个用 social security number 作索引的名字列表就是一个散列。将某个键值插入到散列后,该散列会自动扩展。散列与 Java 中的 HashMap 和 Hashtable 类很相似。

引用类型其实也是标量,它们类似于 C 语言中的指针,能够指向任何东西。这就允许 Perl 生成一个散列的数组、数组的散列、散列的散列、或是数组的数组(多维数组)。有多种方法来获得引用所指向的内容,或者直接使用引用的名字、或者使用 "->" 操作符。引用是一个涉及范围非常广的问题,可以参考 "perldoc perlref" 参考文档来获得更多相关信息。

C 和 C++ 只有一些固定类型的标量。当程序员要使用数组或哈希散列时,不得不去使用钩子 (hoop) 或是 STL 等外部库。 


Java 中有相当于 Perl 里数组或散列功能的类库,但它们在 Java 语言中并不是那么直接。比如说要对散列上所有元素做操作所需要的时间大约是 Perl 的三倍。

对散列中所有元素进行操作的 Java 代码

import java.util.Enumeration;
import java.util.Hashtable;

Hashtable hi = new Hashtable();
// fill in hi's values

// we can use an Iterator, still a lot of typing
for (Enumeration enum = hi.elements();
     enum.hasMoreElements();)
{
 Object o = enum.nextElement();
 // do something with o
}  

 



对散列中所有元素进行操作的 Perl 代码

# note that this even includes the definition and initialization of
# the hash, and still is more compact than the Java code!

%hash = { a => "hi", b => "hello" };

foreach (values %hash)
{
 # do something with $_


 



Perl 的缺憾
Perl 缺少 C、C++ 和 Java 中的许多特性,但它毕竟是一门完全不同的语言。这几种语言中甚至有许多特性是互相矛盾的。例如 Java 只支持单一继承,而 C++ 则可以有多个父类。这种有冲突的情况下当然不可能继承所有语言的特性,Perl 有它自己处理问题的方法。

由于 Perl 程序能够被连接到 C 的库中(事实上,这也就是 Perl 应用广泛的原因之一),这就使得几乎没有任何 C 或 C++ 能做而 Perl 不能的事情。

与 C 和 C++ 相比而言,Perl 有时欠缺的是运行速度。这的确是一个问题,但是通过良好的编程算法以及 Perl 内置函数的使用,就能够克服这一缺点。

Perl 还不能直接使用 C 和 C++ 的库。必须通过不同的模块和绑定,才能够将这些库中的常量以及函数功能转化成适应 Perl 的样子。这就会导致开发和程序运行的速度降低。但由于 CPAN 库中发布了大量这些方面的模块,因此这个问题并不是那么难以解决,

在训练编程技巧方面,Perl 并不象 C 和 C++ 那样深入人心。它是一门年轻的语言,虽然很受欢迎,但并未被人们普遍接受。然而,大多数的 UNIX 系统上都安装了 Perl,且其他的操作系统也都支持 Perl。

Perl 支持单一继承或多继承、封装以及多态,但这仅仅是通过外部模块或程序员的协同来实现的。也就是说,Perl 语言本身并没有严格的面向对象编程规则,需要程序员自己来实现面向对象。这一点有好也有坏,这就要取决于程序员或项目本身了。

Perl 的线程以及统一字符编码(Unicode)支持远远落后于 Java,也稍微次于 C/C++。Java 从最开始设计就支持线程和 Unicode,而 C/C++ 则比 Perl 拥有更多的时间来调整这方面的正确支持。在 Perl 中,对线程和 Unicode 的支持仍处于起步阶段,但 5.6.0 之后的稳定版本发布之后这一点将得到改观。

Perl 的优势
对于 C/C++/Java 程序员而言,Perl 在某些方面的优势是无价的。例如正则表达式在 Perl 中的实现是轻而易举的,但在 C、C++ 或 Java 中实现起来却很麻烦。隐含的函数声明、不严格的语法、以及象日用文档似的程序结构使得 Perl 更具吸引力。

Perl 并不适合于所有人。它需要读者去适应,却接受它的所有缺点和优点。我们并不是觉得 Perl 酷才采用它,而是因为它的确是一种非常好的工具。如果在解决某个问题时使用其他语言更合适,那么就应该放弃 Perl。一个好程序员的手头总是有好几种有用的工具。

Perl 有一些小的不足,但那些不知疲惫的程序员会忽略掉这些缺点。如果的确需要线程和 Unicode 支持,或是严格的面向对象编程,那么你只好根据这些需要来选择其他更合适的语言了。

Perl 是一门通用的灵活的语言,可以象胶水一样将其他许多不同的模型粘合起来。它能够实现任何过程或函数的算法。通常情况下,Perl 会大大减少开发的时间,因为它对某些常见的任务(例如对散列表中的所有元素做操作)只需要少量的代码。最重要的是,Perl 编程总是相当于一个有趣的学习过程。

关于作者
Teodor Zlatanov,1999 年自波士顿大学毕业并获得计算机工程学士学位。从 1992 年开始就一直从事 Perl、Java、C 和 C++ 方面的编程工作。他的兴趣主要在于文本分析方面的开放源码工作、 3-tired 客户-服务数据库模型、UNIX 系统管理员、CORBA、以及项目管理。您可以通过 tzz@bu.edu 与他联系。


地主 发表时间: 08/08 05:32

回复: Aoming [aoming]   版主   登录
MD,这种东西早就该贴出来了~!
^o^


========================================

 There is more than one way to do it ! 

B1层 发表时间: 08/08 22:40

回复: hugh [hugh]   论坛用户   登录
O

想不到啊
我也想去学学Perl

B2层 发表时间: 08/09 16:52

回复: allyesno [allyesno]   论坛用户   登录
偶的机子上装了5。8 自学5。6中

B3层 发表时间: 08/13 10:35

回复: Aoming [aoming]   版主   登录
来概览一下Perl能做什么,以及基本的 Perl 包含的内容
Perl for CGI、PerlScript、数据库、网络编程、以及Perl所以能强大的关键所在――“丰富多采”的模块,其实这O'REILLY的英文书读起来感觉还挺好,有点后悔以前“舍不得”看了
引用:

1.1 What's Perl Good For?
Perl has the advantage of being easy to learn if you just want to write simple scripts - thus its appeal to the ever-impatient system administrator and the deadline-driven CGI developer. However, as you become more ambitious, Perl lets you act on those ambitions. Chapter 2, Installing Perl, covers how to get and install Perl, and Chapter 3, The Perl Interpreter, through Chapter 6, Debugging, cover the basics of the Perl language, its functions, and how to use the Perl debugger.

On top of the Perl language itself, however, are the Perl modules. You can think of modules as add-ons to the Perl language that allow you to streamline tasks by providing a consistent API. Perl itself is fun to use, but the modules lend Perl even more flexibility and enormous power. Furthermore, anyone can write and distribute a Perl module. Some modules are deemed important enough or popular enough to be distributed with Perl itself, but very few are actually written by the core Perl developers themselves. Chapter 7, Packages, Modules, and Objects, introduces you to Perl modules, and Chapter 8, Standard Modules, covers the standard modules that are distributed with Perl itself. 

The most popular Perl module is CGI.pm, which gives a simple interface to developing CGI (common gateway interface) applications in Perl. While Perl itself is indispensable for many different tasks, its text-manipulation features make it perfect for CGI development on the Web. In fact, the resurgence of Perl over the past few years must be credited to its popularity as a CGI language. Chapter 10, The CGI.pm Module, and Chapter 11, Web Server Programming with mod_perl, talk about using Perl for CGI, including mod_perl, which merges Perl into the Apache web server.

Database interconnectivity is one of the most important functions of any programming language today, and Perl is no exception. DBI is a suite of modules that provide a consistent database-independent interface for Perl. Chapter 12, Databases and Perl, covers both DBI and DBM (the more primitive but surprisingly effective database interface built directly into Perl).

The Internet doesn't start and stop at CGI. Network programming is another of Perl's strengths, with a robust sockets interface and several modules for writing clients and servers for all sorts of Internet services - not only the Web, but also email, news, FTP, etc. Chapter 13, Sockets, through Chapter 17, The LWP Library, cover the modules for developing fully functional Internet applications in Perl.

Perl programs are traditionally command-line-based, but the Perl/Tk extension can provide Perl programs with graphical user interfaces, for both Unix and Microsoft Windows. Chapter 18, Perl/Tk, gives a complete reference to Perl/Tk.

Finally, although Perl is primarily developed for Unix, recent releases of Perl for Windows 95 and Windows NT are gaining popularity, both for CGI and system administration tasks. Chapter 19, Win32 Modules and Extensions, covers the Win32 modules for Perl. Web developers on Win32 machines can use a variation of Perl called PerlScript, for JavaScript-like programming over the Web. Chapter 20, PerlScript, gives an introduction to PerlScript and summarizes its syntax and functions.

As you may have noticed, this section entitled "What's Perl Good For" has sneakily become a description of the contents of this book. This book aims at being a general-purpose reference to all things Perl




B4层 发表时间: 08/18 04:23

回复: Neptune [admin_20cn]   论坛用户   登录
老大又在度人了!

B5层 发表时间: 08/18 07:08

回复: shesh [shesh]   版主   登录
屎蛋,哈哈.

B6层 发表时间: 08/18 09:24

论坛: 编程破解

20CN网络安全小组版权所有
Copyright © 2000-2010 20CN Security Group. All Rights Reserved.
论坛程序编写:NetDemon

粤ICP备05087286号