设为首页 收藏本站
查看: 834|回复: 0

[经验分享] Perl编程备忘

[复制链接]

尚未签到

发表于 2015-12-26 12:51:31 | 显示全部楼层 |阅读模式
  这个“备忘”中所有的中文名词与flamephoenix的Perl 5教程一致。对于这些基本名词我都不加解释,有疑问请到这里查询。
  1. 关联数组和复杂数据
  Perl不支持“结构”和“类”,然而它还是有办法实现复杂的数据结构的,工具就是“关联数组(Hash)”和“引用(reference)”。关联数组是一个以索引(key)来取得值(value)的对照表,然而当我们把关联数组的值定义成一个引用的时候,关联数组就有了更多的灵活性。引用在C++里是一个已经存在的概念,Perl里的引用更类似于指针,它能够指向任何的数据结构
  假设一个学校按以下结构处理它的学生成绩单数据,学校下面是以班号为索引的班级,班级下面是以学号为索引的学生。学生有名字生日等一些信息。每个学生选修的课程不一样,以课程名字为索引,下面是课程成绩。是如下的一种
  %hashSchool->$nClassNo->$nStdNo->'Name'=$szStdName
%hashSchool->$nClassNo->$nStdNo->'Birth'='2079-9-15'
%hashSchool->$nClassNo->$nStdNo->'courses'->'Quatum Mechanics'='A'
%hashSchool->$nClassNo->$nStdNo->'courses'->'History of Art'='B'
  那么一个给定学生名字和生日,要求打印他的所有成绩单的Perl子程序如下(假设%hashSchool已经有了内容):
  using Data::Dumper;
  $szStdName = "Sebastien Ouyang";
$szStdBirth = '2090-3-22';
&PrintTranscript( \%hashSchool, $szStdName,$szStdBirth);
  sub PrintTranscript{
    my ($rHashSchool, $szStdNameQuery, $szStdBirth) = @_;
   
    while( my($nClassNo, $rClass) = each %{$rHashSchool}){
    while( my($nStdNo, $rStd) = each %{$rClass}{
    if( ($rStd->{'name'} eq $szStdNameQuery) and ($rStd->{'birth'} eq $szStdBirth)){
        print Dumper( $rStd);
}
}
}
}
为了简化只找出第一个匹配的学生,当然实际中得找出所有匹配的学生放到一个列表再做处理。警告:在遍历关联数组的过程中最好(只是说最好,其实有些情况还是需要的)不要对它增加或者删除任何元素,否则会产生预想不到的效果。
  2. 文件句柄
Perl的变量名命名方法是类似Basic的,用前置的符号%, @, $等来表示变量类型。但是有一个例外,就是文件句柄,它可以没有前置符号。但是这样就有个问题,怎么定义它的作用范围是my, local还是global呢?如果全都是global,没准就会产生冲突。可以使用FileHandle包
use FileHandle;
my $FH = new FileHandle("file");
$FH->close();
上面句子的作用和下面相同
open(FH, "file");
close(FH);
取文件的一行的用法
$line = <FH>;
$line = $FH getline();
  3. 可变长参数列表
在C++里,用&#8220;重载&#8221;的方式定义了对同一个函数名,不同参数列表的函数的调用方式。如果你能深入到C++生成的link符号文件,会发现这些函数会生成不同的函数体。在这一点山Perl拥有优势,它各每个函数生成参数栈列表@_,对参数栈还有灵活的shift/pop操作。
  举例子来说,你需要一个Max函数找出一堆数里面的最大值,但是你不确定会有多少个数。
$nMax = &Max(1, 2, 9);
$nMax = &Max(1.0, 2.9, 9, 3.0e3);
  sub Max{
my(@values) = @_;
my $nMax = $values[0];
foreach $value (@values){
    $nMax = $value if( $value > $nMax);
}
或者另外一种写法
sub Max{
my $nMax = shift;
while( @values){
    $value = shift;
    $nMax = $value if( $value > $nMax);
}
}
@_是本地的(my), 所以perl的函数支持递归调用。另外一个要注意的是,Perl从来不复制传递给子函数的参数,也就是说,Perl没有&#8220;按值传递&#8221;的说法。所以在子函数里改变@_[0]的值,上一级函数里对应的调用参数就真的改变值了。
  4. 正则表达式的一些特性
4.1 匹配多行
/s选项可以对一个内部包含换行符号的字符串进行匹配。例如
$string = "This is a\n mutiple line string.";
$string =~ /This.*strin/s;
不用/s会导致'.'不匹配换行,下面的匹配会失败。
$string =~ /This.*strin/;
4.2 多重匹配
通常正则表达式第一次找到匹配的字符串就返回。用/g选项和while循环配合可以多次匹配。假设一个C语言文件已经整个被读入@line,我们要打印出里面所有的用/*和*/包含的注释。当然这些注释是可以跨行的,所以也要用到上面的/s选项。
my $lines = '';
foreach $string (@line){
    $lines .= $string;
}
while( $lines =~ /\/\*(.*?)\*\//gs){
    print $1;
}
一定要注意,在while循环中不可以改变$lines的值,否则有陷入死循环的危险。如果一定要改变,用另外一个变量。
4.3 非
^在正则表达式中被用来作为&#8220;行首&#8221;要求。但是它还有一个功能,加在某个字母前表示&#8220;非&#8221;。例如
$string = "a*b*c*def";
$string =~ /[^*]+/;
表示匹配非*的任意长字符串,第一次会得到'a'.
4.4 替换时的必须品quotemeta()
在正则表达式里,特殊字符前必须加一个反斜杠'\'。如何判断一个字符串里有多少特殊字符要做这个处理?Perl提供了函数quotemeta()来做这个事情。
$string = '+-*/&^%';
$substr = '+-*';
$substr = quotemeta( $substr);
$newsub = 'Add/Sub/Mult';
$string =~ s/$substr/$newsub/;
注意新内容$newsub一定不要用quotemeta处理。
  5. 结构化编程
在C语言的结构化编程方式中,常常会把属于相同类型的函数(比如说,文件处理,或者音频处理)放到同一个.c文件中。Perl也可以这样。通常会把一个项目分成一个.pl文件和若干个.ipl(也可以用别的后缀名,但这个是最流行的)文件。ipl文件里面放一些子函数,它的写法和.pl文件并没有本质区别,但是要在文件头部加上package __ABC__;(这里假设你定义自己的模块的名字叫ABC);在文件最后加上一行字1;表示有缺省的返回值。
  在pl文件里要这样调用ipl里面的子函数:首先要在文件头部宣称require "abc.ipl";(假设ipl文件名就是abc.ipl),然后在文件里就可以用 __ABC__::abcdef()来调用abc.ipl里面的子函数abcdef()了。
  6. 模块与名字空间
上面说的require是Perl的一个语句,用户可以这样
if( $szInput = 'a'){
    require 'a.ipl';
}else{
    require 'b.ipl';
}
在Perl程序运行到这个if语句以后,才能决定载入哪个ipl文件。这样很灵活,但是也很糟糕,因为有可能在运行到这句程序已经执行了一个小时,然后载入b.ipl,到了这时候发现b.ipl中有语法错误,这样就浪费了一个小时的机时。所以最新的潮流是鼓励使用use,而不是require. use不能像一个语句一样使用,只能放在文件头部,在编译时所包含的模块文件就会被检查。
  生成一个use模块需要做以下事情:
(1) 生成一个后缀.pm的文件,例如abc.pm。在.pm文件的头部必须有package abc;--在这里模块的文件名等于模块的包名,模块的包名等于模块的名字空间名。模块的名字可以是这样package AAA::abc, 这样可以方便把一些模块归类到A。
(2) 要使用模块,在程序里声明use abc; 之后就可以abc::xyz()来调用abc里的函数xyz.
(3) 可以在.pm文件中包含一个import()函数,它将在模块被use的时候自动执行。注意use是可以带参数的,这个参数就传给了import(). 例如
use abc 2.31;
在.pm里
package abc;
my $_actualversion = 2.50; # this modoule version is 2.50
sub import{
    shift;    #注意第一个参数是包名'abc'
    my $version = shift;
    if( $version > $_actualversion){
        die "You require version $version and this is $_actualversion\n";
}
}
1;
以上代码被普遍用于对模块的版本做检查。
  7. 在使用use strict时使用全局变量
以下代码是不对的
use strict;
$string = 'a';
需要这样
use strict;
use vars qw($string);
$string = 'a';
  8. %INC和@INC
C程序员一定很熟悉以下代码
#ifndef _HEADER_A_
#define _HEADER_A_
#include "header.h"
......
#endif
以上代码是为了防止一个头文件被多次包含。Perl要聪明一些,它会把所有已经调用的模块保存在%INC中,调入新的模块前会先查看一下是不是已经调入了。另外,对于特别大的工程,模块有重名冲突的危险,这时可以打印出这个关联数组:
use abc;
while( my($key, $value) = each %INC){
    print "$key => $value\n";
}
  将会打印出
abc => /usr/local/lib/myperl/abc.pm
  @INC存储的是在Perl中可用的路径。有4种设置方式
(1) $ export PERL5LIB="my_path"
(2) use lib "my_path" 推荐这种方式
(3) unshift(@INC, "my_path");
(4) 修改Perl的config.sh文件

运维网声明 1、欢迎大家加入本站运维交流群:群②:261659950 群⑤:202807635 群⑦870801961 群⑧679858003
2、本站所有主题由该帖子作者发表,该帖子作者与运维网享有帖子相关版权
3、所有作品的著作权均归原作者享有,请您和我们一样尊重他人的著作权等合法权益。如果您对作品感到满意,请购买正版
4、禁止制作、复制、发布和传播具有反动、淫秽、色情、暴力、凶杀等内容的信息,一经发现立即删除。若您因此触犯法律,一切后果自负,我们对此不承担任何责任
5、所有资源均系网友上传或者通过网络收集,我们仅提供一个展示、介绍、观摩学习的平台,我们不对其内容的准确性、可靠性、正当性、安全性、合法性等负责,亦不承担任何法律责任
6、所有作品仅供您个人学习、研究或欣赏,不得用于商业或者其他用途,否则,一切后果均由您自己承担,我们对此不承担任何法律责任
7、如涉及侵犯版权等问题,请您及时通知我们,我们将立即采取措施予以解决
8、联系人Email:admin@iyunv.com 网址:www.yunweiku.com

所有资源均系网友上传或者通过网络收集,我们仅提供一个展示、介绍、观摩学习的平台,我们不对其承担任何法律责任,如涉及侵犯版权等问题,请您及时通知我们,我们将立即处理,联系人Email:kefu@iyunv.com,QQ:1061981298 本贴地址:https://www.yunweiku.com/thread-156561-1-1.html 上篇帖子: 比较Perl、PHP、Python、Java和Ruby 【转载】 下篇帖子: perl转载undef简介 defined函数简介
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

扫码加入运维网微信交流群X

扫码加入运维网微信交流群

扫描二维码加入运维网微信交流群,最新一手资源尽在官方微信交流群!快快加入我们吧...

扫描微信二维码查看详情

客服E-mail:kefu@iyunv.com 客服QQ:1061981298


QQ群⑦:运维网交流群⑦ QQ群⑧:运维网交流群⑧ k8s群:运维网kubernetes交流群


提醒:禁止发布任何违反国家法律、法规的言论与图片等内容;本站内容均来自个人观点与网络等信息,非本站认同之观点.


本站大部分资源是网友从网上搜集分享而来,其版权均归原作者及其网站所有,我们尊重他人的合法权益,如有内容侵犯您的合法权益,请及时与我们联系进行核实删除!



合作伙伴: 青云cloud

快速回复 返回顶部 返回列表