perl语言学习记录

                               perl入门
                               ========

Author:
Date: 2012-12-05 23:05:55 中国标准时间


Table of Contents
=================
1 perl的变量
    1.1 变量声明
        1.1.1 声明变量类型
        1.1.2 声明变量作用域
    1.2 特殊变量
    1.3 变量定义
    1.4 变量作用域
2 子程序
    2.1 定义
    2.2 调用
    2.3 参数
    2.4 返回值
3 perl选项及帮助
4 控制结构
    4.1 unless控制结构与if结构相反
    4.2 until控制结构与while结构相反
    4.3 for控制结构
    4.4 last、next、redo操作符
    4.5 perl支持条件修饰词
    4.6 given-when控制结构
    4.7 goto语句
    4.8 裸块
5 操作符与函数
    5.1 比较符
    5.2 操作符
        5.2.1 \    #获取其他数据结构的引用(类似C指针),可以保存在标量中,类似&
        5.2.2 $、@、%   #取得被引用的实际标量、列表、散列(类似C中的*运算符)
        5.2.3 ->   #与C类似,二元操作符->是一个中缀析值操作符
        5.2.4 ++/-- #自增操作符可以对字符串进行操作,自减会讲字符串转换为数字再自减
        5.2.5 ../...
        5.2.6 COND?THEN:ELSE   #
        5.2.7 =>
        5.2.8 -     #取负操作符可以对字符串操作
        5.2.9 ~     #按位取反
        5.2.10 **    #指数运算符
        5.2.11 =~    #绑定操作符,把一个字符串和一个模式进行匹配、替换绑定在一起,要不然这些操作会对$_操作,返回值指示右边的操作符是成功还是失败的。
        5.2.12 !~    #类似=
        5.2.13 <>   #顺序处理所有输入和所有文件
        5.2.14 //   #定义否操作符,别把他当做注释符
        5.2.15 ~~智能匹配操作符
        5.2.16 x用于重复字符串或列表
        5.2.17 .操作符用来连接两个字符串
        5.2.18 m/正则表达式/[匹配选项] #模式匹配
        5.2.19 s/被替换的正则表达式/替换值/[替换选项] #正则表达式替换,默认只进行一次替换
        5.2.20 tr/被替换的字符/替换的字符/     #字符替换
        5.2.21 文件测试操作符
    5.3 函数
        5.3.1 print
        5.3.2 open
        5.3.3 对文件句柄进行输入输出
        5.3.4 对目录句柄进行输入输出
        5.3.5 select:改变默认的文件句柄
        5.3.6 hash变量的函数
        5.3.7 split操作符根据分隔符拆开一个字符串
        5.3.8 join函数将片段联合成一个字符串
        5.3.9 glob函数 #把通配符展开成相匹配的文件名
        5.3.10 字符串函数
        5.3.11 sort函数
        5.3.12 defined函数
        5.3.13 undef函数
        5.3.14 splice 删除、替换列表的切片 splice 列表 偏移位置 [长度[替代列表]]
        5.3.15 grep 函数
        5.3.16 map函数
        5.3.17 delete函数
        5.3.18 读取二进制文件的函数
6 模块
    6.1 require "dumpvar.pl";
    6.2 use Storable;
7 高级专题
    7.1 正则表达式
        7.1.1 不捕获模式
        7.1.2 命名捕获(use 5.010;)
        7.1.3 \U,\L,\E
        7.1.4 \u.\l
        7.1.5 非贪婪量词
        7.1.6 锚点(anchor)允许你限制模式能在什么地方匹配。
    7.2 用inline模板结合C与perl
        7.2.1 Perl调用C
        7.2.2 C调用Perl
    7.3 perl的面向对象编程
8 语言特性


1 perl的变量
-------------

1.1 变量声明
=============

1.1.1 声明变量类型
~~~~~~~~~~~~~~~~~~~
   1. $变量名
      --定义一个标量变量
      --($var)是标量,处在标量上下文中
   2. @变量名
      --定义一个列表变量
      $#array返回array列表最后元素的索引。
      对于单元素数组,$#array返回0,对于空数组,$#array返回-1.
      NOTE:
      由于列表变量中只能存放标量,故要实现散列数组这种数据结构,只能通过标量引用散列的方式实现
   3. %变量名
      --定义一个hash变量
      --hash变量可以转换成列表变量
      --hash变量之间赋值时,先转换成列表,再赋值转换成hash变量
      --hash变量用胖箭头指示的时候,整个列表用一个额外的逗号结束
   4. $hash{$key}
      --引用hash中的值,注意用大括号!!
      --hash中的key只能是字符串
   5. &子例程
      --定义一个子例程
   6. *变量名
      --定义一个typeglob类型
      有时候你想命名一个所有叫做foo的东西,而不管它的类型指定字符是什么,因此符号可以用一个前缀*命名,这里*代表所有的类型字符。我们把这些东西成为typeglob,而且他们又好几种用途。他们也可以用作左值。给一个typeglob赋值就是perl从一个符号表向另外一个导入符号的实现。
   7. 同一个变量在标量上下文和列表上下文中表示的值是不同的
   8. 包中的变量:包::变量
      包名::$标量名
      包名::@数组名
      包名::%hash名
   9. ${some_expression()}的方式实现间接引用变量
      有时,在编译时你并不知道想要的名字是什么。有时候你希望间接地命名一些东西,Perl提供了一种机制:你总是可以用一个表达式块代替字母数字的变量名,这个表达式返回对一个真实数据的引用,比如


  $a=b;
  $b=2;
  ${$a}=$b=2;

   10. 同某些shell一样,可以在变量名周围放大括号,使之与后面的数字、字母区分开来


  $a="b";
  print "${a}b"; #打印出bb

1.1.2 声明变量作用域
~~~~~~~~~~~~~~~~~~~~~
   1. my 变量
      --定义块内的私有变量
      --在my不适用括号时,只用来声明单个词法变量
   2. our 变量
      进行有选择的访问全局变量
   3. local 变量
      给全局变量提供临时值
   4. state 变量
      --声明持久性的私有变量(静态变量)
      --即,它为私有变量,但是它的值在每次进入代码块的时候不会被初始化,还保持上次的值
      --在列表上下文环境中,不能用state变量
   5. 当同时对多个变量进行声明作用域时,列表必须放在小括号里。

1.2 特殊变量
=============
1. $_     --省略变量时,一般用$_代替省略的变量
2. $!     --存放错误信息
3. $0     --保存文件名
4. %ENV   --该hash变量存储了环境变量
5. $&     --字符串里实际匹配模式的部分会被自动存进$&里
6. $`     --匹配起始位置之前的字符串会存在$`中                       #反引号
7. $'     --匹配结束位置之后的字符串则存在$'里
8. $^I    --当设置了$^I值后,<>会将原文件保存为以$^I为后缀的备份文件,并自动写文件
9. %SIG   --对特殊hash%SIG赋值就能设置信号处理程序,哈希键是信号名称,值为信号处理程序名
10. $$|$?    --跟bash一样
11. __FILE__、__LINE__、__PACKAGE__   #程序某点的文件名,当前行号和包名。
12. __END__(或者C-D、C-Z控制字符)      #在真正的文件结束符之前表示脚本的逻辑结束。任何后面的文本都被忽略,不过可以通过DATA文件句柄读取
13. __DATA__     #作用类似__END__记号,不过它是在当前包的名字空间打开DATA句柄,可以用<DATA>文件句柄按一个普通文件来读
14. #ARGV        #参数的个数,不包括程序名
15. @ARGV        #传入的参数列表,不包括程序名

1.3 变量定义
=============
   1. (a,b,c...)              #定义一个数组
   2. [a,b,c...]              #定义一个数组的匿名引用
   3. {a=>1,b=>2,c=>3...}     #定义一个散列,或散列的匿名引用


  #Perl可以用简单的标量来代表复杂的数据结构
  $kids_of_wife{"Jacob"}={
         "Leah"=>["Reben","Simeon","Levi"],
         "Rachel"=>["Joseph","Benjamin"],
         "Bilhah"=>["Dan","Naphtali"],};
  $kids_of_wife{"Jacob"}{"Leah"}[0]="Reben";

   4. 引起结构,
      常用         通用        含义                  可否内插
      ''           q//        直接量字符串            否
      ""           qq//       直接量字符串            是
      ``           qx//       执行命令                是
      ()           qw//       单词列表                否
      //           m//        模式匹配                是
      s///         s///       模式替换                是
      y///         tr///      字符转换                否
      " "          qr//       正则表达式              是
      分隔符(引起字符)可以换成其他符号,如


  $a=q!abc!;
  $b=qq($a equals 'abc');

      可以在引起指定字符和其起始包围字符之间使用空白。如:


  $chunk_of_code=q{
       if($condition){
            print "Gotcha!";
       }
  }

      对于s///和tr///这样的两元素构造而言,如果第一对引号是括号对,那么第二部分将获取自己的引号字符。实际上,第二部分不必与第一对一样。如


  s<foo>(bar)或tr(a-f)[A-F]

   5. 任何在语法中没有其他解释的名字都会被当做一个引起字符串看待。我们叫它们裸字。完全由小写字符组成的裸字在将来也可能有和保留字冲突的危险。
      可以用use strict 'subs';来废止裸字的使用。可以用no strict 'subs'取消废止
   6. 多维数组
      perl没有多维数组,通过使用匿名引用来仿照多维数组


  my @matrix =(
        [1,2,3],
        [11,12,13],
        [21,22,23]
  };

      注意使用方括号[]来声明矩阵的行数

1.4 变量作用域
===============
   1. 在控制条件中定义的变量,其作用域只扩展到其余条件的作用域,包括任何随后可能存在的elsif和else子句,但是不会超过这个作用域
   2.

2 子程序
---------

2.1 定义
=========
   sub 程序名(参数说明){
   ...
   }
   对于参数的说明为:
   1. 参数类型的说明
      $  :标量
      @  :列表
      %  :散列
      &  :函数引用
      *  :类型通配
      \@ :列表引用,此时传入的列表会自动转化为列表引用
      \% :散列因哟个,此时传入的散列会自动转化为散列引用
      如:sub a($$)代表这个子程序的参数为两个标量
      sub b(\@\@)表示这个子程序的参数为两个列表引用
   2. 可选参数的说明
      此外,可以用;将强制参数与可选参数分隔来完成。例如
      sub a($$;$)可以传入2个标量或3个标量
   3. 空参数定义的说明
      空参数定义说明子程序可以带任何类型的任何数量的参数

2.2 调用
=========
   &程序名

2.3 参数
=========
   1. 参数被放到@_列表变量中,可以用$_[0],$_[1]...来获取
   2. 给子程序传递文件句柄
      在参数中传递文件句柄时,perl将这个参数当做一个纯单词,只是将文件句柄的字符串传递给子程序。 因此,需要用Symbol模块中的qualify_to_ref将单词转换回文件句柄:


  use Symbol;
  sub print_it(*)
  {
      my $file_handle = qualify_to_ref(shift,caller);
  }
  print_it(STDOUT);

2.4 返回值
===========
最后执行的语句作为子程序的返回值

3 perl选项及帮助
-----------------
1. use strict  --使得perl更严厉
2. 在程序开头的地方,用use指令来声明其他CPAN中的模块。例如
3. 可以在use声明中加上导入列表来指明要它提供哪些函数


  use File::Basename qw/basename,dirname/
  #use File::Basename ("basename","dirname")
  my $name="/usr/local/bin/ls";
  my $basename=basename $name;

4. 导入函数的目的,是使用简短的函数名称,然后,哪怕不导入这些名词,也可以通过全名的方式来调用相应的函数


  use File::Basename ()  #不导入File::Basename模块中的任何函数
  my $name="/usr/local/bin/ls";
  my $basename=File::Basename::basename $name;  #全名的方式调用basename函数

5. 模块也有面向对象方式的模块,这种模块不用考虑导入的函数名冲突的问题
6. 获取帮助
   1. 文档说明
      手册页           内容
      perl            存在那些perl手册页
      perldata        数据类型
      perlsyn         语法
      perlop          操作符和优先级
      perlre          正则表达式
      perlvar         预定义变量
      perlsub         子例程
      perlfunc        内置函数
      perlmod         如何令perl模块工作
      perlref         参考手册
      perlobj         对象
      perlipc         进程间通讯
      perlrun         如何运行perl命令,以及命令行开关
      perldebug       调试
      perldiag        诊断信息
      FAQ:
      perlfaq1        关于perl的通用信息
      perlfaq2        获取和学习perl
      perlfaq3        编程工具
      perlfaq4        数据操作
      perlfaq5        文件和格式
      perlfaq6        正则表达式
      perlfaq7        通用perl语言信息
      perlfaq8        系统交互
      perlfaq9        网络
      平台相关信息
      perlamiga       Amiga移植
      perlcygwin      Cygwin移植
      perldoc         Dos移植
      perlhpux        HP-UX移植
      perlmachten     Power MachTen移植
      perlos2         OS2移植
      perlos390       OS390移植
      perlvms         DEC VMS移植
      perlwin32       Windows移植
   2. 获取帮助的方式
      1. man perl
      2. perldoc 模块名
         搜索所有手册页收集的目录
         perldoc -f 关键字
         搜索内容含关键字的文档
      3. 到perl5.6.1时,每个主要的perl手册都有自己的搜索和显示能力。你可以用手册页名字进行搜索,并且传递一个perl正则表达式作为搜索模式
         搜索所有FAQ,使用perlfaq命令


  perlop comma
  perlfunc split
  perlvar ARGV
  perlfaq round

      4. perltoc命令搜索所有手册页收集的目录
      5. 或者搜索全部perl在线文档,包括所有标题、描述和例子,对于任何字符串的实例,使用perlhelp命令

4 控制结构
-----------

4.1 unless控制结构与if结构相反
===============================
1. unless控制结构
unless){
...}else{
...}
2. if控制结构
if(){
...}elsif(){
...}else{
...}

4.2 until控制结构与while结构相反
=================================
   1. 可以有
      do{
      ......
      }until ......
      的写法
   2. while和until语句可以有一个额外的块:continue块。么次继续执行到这个块时,它就会执行一次,不管是退出第一个快,还是用一个明确的next
   3.

4.3 for控制结构
================
1. perl的for控制结构跟C语言中的for循环类似
for(initialization;test;increment){
body;
body;
}
2. perl中for和foreach两个关键字是等价的。例如


  for(1..10){  #和一个从1到10的foreach循环一样
  print "I can count to $_!\n";
  }

3. foreach循环能够处理$_在多层循环中的多版本重用

4.4 last、next、redo操作符
===========================
1. 操作符last能立即终止循环,就好像C语言中的break一样
2. next操作符不立即退出循环,但是立即结束这次迭代,就好像C一类语言中的continue操作符
3. redo能将控制返回到本次循环的顶端,不经过任何条件测试,也不会进入下一次循环迭代,只是重做本次循环体操作
4. 在某个循环块加上标签,通常只要将标签及一个冒号放在循环前面就行了。之后在循环里,若有需要就可以在last、next和redo的后面填上这个标签
   注意,该标签是对整个循环命名,而不是goto LABEL的意思!
5. last操作符立即退出当前循环。即使有continue块也不会执行
   redo操作符也不执行continue块
   next操作符会执行continue块
6.

4.5 perl支持条件修饰词
=======================
1. 修饰词的两边都只能写单个表达式
2. 使用foreach修饰词的时候无法自选控制变量

4.6 given-when控制结构
=======================
1. given-when能够根据given的参数,执行某个条件对应的语句块。类似C语言的switch语句
2. 语法为


  use 5.010;
  given($ARGV[0]){
  when(/fred/i){say 'Name has fred in it'}
  when('Fred') {say 'Name is Fred'}
  default      {say "I don't see a Fred"}
  }

given会将参数化名为$_,每个when条件都尝试用智能匹配符~~对$_进行测试,相当于


  use 5.010;
  given($ARGV[0]){
  when($_~~/fred/i){say 'Name has fred in it'}
  when($_~~'Fred') {say 'Name is Fred'}
  default      {say "I don't see a Fred"}
  }

3. 也可以在when中书写任何的判断语句
4. 与if-elsif-else不同,given-when可以在满足某个条件的基础上,继续测试其他条件,若在语句块中添加break语句则不继续执行下面的条件判断,若后面语句块添加continue则继续执行下面的条件判断
5. default相当于一个永远为真的判断
6. 将foreach替代given则表示对数组内所有元素都一一进行操作,例如


  use 5.010;
  foreach(@name){
  say "Processing $_";
  when(/fred/i){say 'Name has fred in it'}
  when('Fred') {say 'Name is Fred'}
  default      {say "I don't see a Fred"}
  }

4.7 goto语句
=============
   1. goto LABLE
      找出用LABEL标记的语句,并从那里重新执行。它不能用于跳进任何需要初始化的结构,也不能跳进一个已经优化了的结构
   2. goto EXPR
      goto EXPR是goto LABEL的一般形式,它期待EXPR表达式生成一个标记名称
   3. goto & NAME
      它不是传统的goto使用,它把正在允许的子例程替换为一个对命名子例程的调用。

4.8 裸块
=========
   1. 一个Block本身等效于一个执行一次的循环,所以你可以用last退出一个块或者用redo重新运行块
   2. 对于eval{},sub{},do{},他们不是Block,而是一个语句

5 操作符与函数
---------------

5.1 比较符
===========
   1. 数字比较:==、!=、<、<=、>、>=、<=>
   2. 字符串比较:eq ne lt le gt ge cmp

5.2 操作符
===========
   1. 有些“函数”实际上都是一元操作符,如gethostbyname,delete,defined等

5.2.1 \    #获取其他数据结构的引用(类似C指针),可以保存在标量中,类似&
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    \给它后面的东西创建一个引用。在列表上使用时,他创建一列引用。


  @myarray=(1,2,3,4);
  $ary=\@myarray;        #引用一个命名数组
  $hsh=\%myhash;         #引用一个命名散列
  $sub=\&mysub;          #引用一个命名子例程
 
 
  $ary=[1,2,3,4,5];      #引用一个未命名数组
                         #[]告诉perl创建一个新数组,并返回对它的一个引用
  $ary=[@myarray]        #[]也可以创建一个数组的拷贝,并返回一个对它的匿名引用
  $hsh={Na=>19,c1=>35};  #引用一个未命名散列
  $hsh={%myhash};        #{}也可以创建一个散列的拷贝,并返回一个对它的匿名引用
  $sub=sub{print $state};#引用一个未命名子例程
  $fido=new Camel "Amelia"; #引用一个对象

5.2.2 $、@、%   #取得被引用的实际标量、列表、散列(类似C中的*运算符)
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~


  @array=(1,2,3);
  $ref=\@array;
  push(@$ref,4);  #@array==(1,2,3,4)

5.2.3 ->   #与C类似,二元操作符->是一个中缀析值操作符
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    1. 如果右边是一个[...]数组脚标、一个{...}散列脚标或者一个(...)子例程参数列表,那么左边必须是一个对应的数组、散列或子例程的引用(硬应用或符号引用都行)


  $arrayRef->[42]        #一个数组析值
  $hashRef->{"corned beff"}   #一个散列析值
  $subRef->(1,2,3)        #一个子例程析值

    2. 它是某种类型的方法调用,右边必须为一个方法名或包含该方法名的简单标量变量。左边必须是一个对象名或一个类名称(即包名称)


  $yogi=Bear->new("Yogi");      #一个类方法调用
  $yogi->swip($picnic);         #一个对象方法调用

5.2.4 ++/-- #自增操作符可以对字符串进行操作,自减会讲字符串转换为数字再自减
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    若自加的变量在字符串环境中使用,而且该值非空,且匹配模式/^[a-zA-Z]*[0-9]*$/则自增是以字符串方式进行,每个字符都波流在其范围之内,同时还会进位。
    但是自减不行,如:


  $a="b";
  $a++;         #$a=c
  $a--;         #$a=-1
  $a="9b";
  $a++          #由于不匹配/^[a-zA-Z]*[0-9]*$/所以先转换为数字再自加,$a=10

5.2.5 ../...
~~~~~~~~~~~~~
    1. 在数组环境下,返回一个列表,若左值小于右值则返回空列表,可以用于字符串


  for (101 .. 200) {print;}
  @alphabet=('A' .. 'Z')
  @combos={'aa' .. 'zz')

    2. 在标量环境下,.. 返回一个布尔值,模仿了sed,awk和各种编辑器的行范围操作符。只要他的左操作符为假就一直为假,一旦左操作符为真,该范围操作符就保持真的状态直到由操作数为真,右操作数为真之后该范围操作符再次为假。

5.2.6 COND?THEN:ELSE   #
~~~~~~~~~~~~~~~~~~~~~~~~~
    1. 不管选择了那个参数,标量或列表环境都传播到该参数,COND参数总在标量环境中,因为它是一个条件


  $a=$ok?$b:$c;   #得到标量
  @a=$ok?@a:@c;   #得到列表
  $a=$ok?@b:@c;   #得到列表的计数
  #?:的结果可以做为左值
  ($a_or_b ?$a:$b)=$c;

5.2.7 =>
~~~~~~~~~
    =>大多数时候就是逗号操作符的同义词,对那些成对出现的文档参数很有用。它还强制把它紧左边的标识符解释为一个字符串

5.2.8 -     #取负操作符可以对字符串操作
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    若字符串以+/-开头时,-操作符会将其改为-/+开头
    若字符串不以+/-开头,则操作符在字符串前添加-

5.2.9 ~     #按位取反
~~~~~~~~~~~~~~~~~~~~~~
    如果~的参数是字符串而不是数字,则返回等长字符串,但是字符串的所有位都是互补的。这是同时反转所有位的最快方法,而且它还是可移植的反转位的方法,因为它不依赖于机器的字的大小

5.2.10 **    #指数运算符
~~~~~~~~~~~~~~~~~~~~~~~~~
    1. 指数运算比一元运算的优先级高,故


  -2**2==-(2**2)==-4

    2. 指数运算是右结合的


  2**3**4==2**(3**4)

5.2.11 =~    #绑定操作符,把一个字符串和一个模式进行匹配、替换绑定在一起,要不然这些操作会对$_操作,返回值指示右边的操作符是成功还是失败的。
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

5.2.12 !~    #类似=
~~~~~~~~~~~~~~~~~~~~

5.2.13 <>   #顺序处理所有输入和所有文件
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
将参数指定的文件名或者是标准输入中获取输入流
文件名为-的话,意味着标准输入
由于<>会处理所有的输入,所以在使用第一个<>进行读取的while循环中,接着使用第二个<>的话,几乎是错误的,除非重新初始化了@ARGV数组
若<>不能打开某个文件,会报出信息,然后自动跳到下一个文件中

5.2.14 //   #定义否操作符,别把他当做注释符
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
在发现左边已定义的值时进行短路,不论左边的值是真是假。例如


  use 5.010;
  $last_name=0
  my $last_name=$last_name // "No last Name";    #返回值为0,只有在$last_name为undef时才会获得后面的值

5.2.15 ~~智能匹配操作符
~~~~~~~~~~~~~~~~~~~~~~~~

5.2.16 x用于重复字符串或列表
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    1. 字符串 x 数字     #返回数字个字符串
    2. 小括号中的列表 x 数字  #x的作用是一个列表复制器

5.2.17 .操作符用来连接两个字符串
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

5.2.18 m/正则表达式/[匹配选项] #模式匹配
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
1. 用法为:
字符串=~m/正则表达式/
2. 列表上下文中使用m//时,如果匹配成功,那么返回的是所有捕获变量的列表,如果匹配失败,则返回空列表
* 匹配选项
  1. /i忽略大小写
  2. /x
  3. /s
  4. /g让模式能够匹配到字符串上的许多地方,一般用于列表上下文
  5. /m当字符串中包含换行符时,让^$能够匹配串中的换行符,这样一来他们所代表的位置就不是整个字符串的头尾,而是每行的开头跟结尾

5.2.19 s/被替换的正则表达式/替换值/[替换选项] #正则表达式替换,默认只进行一次替换
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    替换返回成功替换的数量
* 替换选项
  1. /g进行全局替换
  2. /i,/x,/s与m//一样

5.2.20 tr/被替换的字符/替换的字符/     #字符替换
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

5.2.21 文件测试操作符
~~~~~~~~~~~~~~~~~~~~~~
    1. 所有的文件测试操作符,看起来总是由一个连字符和某个字母组成,字母代表要进行何种测试,后面跟着要测试的文件名或文件句柄
    2. 注意:root用户而言,-r、-R、-w和-W总是返回1,而且如果文件模式设置了执行位,-x和-X也返回1.因此root用于执行脚本可能需要做一次stat来检测文件的真实模式,或者暂时把UID设置为其他用户
* 测试文件权限
  1. -r 测试文件或目录是否对有效用户可读
  2. -w 测试文件或目录是否对有效用户可写
  3. -x 测试文件或目录是否对有效用户可执行
  4. -o 测试文件或目录是否由有效用户拥有
  5. -R 测试文件或目录是否对实际用户或组可读
  6. -W 测试文件或目录是否对实际用户或组可写
  7. -X 测试文件或目录是否对实际用户或组可执行
  8. -O 测试文件或目录是否由实际用户或组所拥有
* 测试文件属性
  1. -e测试文件是否存在
  die "files already exist" if -e $file
  2. -z测试文件是否存在且内容为空,对目录来说永远为假
  3. -M测试文件未修改天数(大多数时间值为分数)
  4. -s测试文件大小,以字节为单位
  5. -A测试文件未访问的天数
  6. -u|g|k测试文件或目录是否设置了setuid|setgid|sticky位
  7. -C测试最后一次inode变更后至今的天数
* 测试文件类型
  1. -f|d|l|S|p|b|c|t测试是否为普通文件|目录|符号链接|socket类型文件|命名管道|块设备文件|字符设备文件|TTY设备
  2. -T|B测试文件看起来像是文本文件|二进制文件,文件不存在则都返回假
* 栈式文件测试操作
  1. 可以用栈式写法将文件测试操作符排成一排,放在要测试的文件名前:
  if (-w -r -x $file){
  print "the mode of $file is 7";
  }
  2. 使用栈式写法,靠近文件名的测试会先执行,次序为从右往左
* stat和lstat函数
  1. ($dev,$inode,$mode,$nlink,$uid,$gid,$rdev,$size$atime,$mtime,$ctime,$blksize,$blocks)=stat($filename);
  2. stat对符号连接名返回所指向对象的信息
  3. lstat专门返回符号连接本身的信息,若不是符号链接,它会返回空列表
* localtime函数
  1. stat获得的时间戳看起来是一个整数,对人来说不好看,可以用localtime函数来转换
  my ($sec,$min,$hour,$day,$mon,$year,$wday,$yday,$isdst)=localtime($timestamp);
  2. $mon的范围从0-11,$year是一个从1900起算的年数,$wday范围从0星期天-6星期六,$yday为0-364
  3. localtime或gmtime函数默认使用当前time返回的时间值
 

5.3 函数
=========
   1. 总是可以用小括号把一个命名的一元操作符转换成函数。记住:如果看起来是函数,那他就是函数

5.3.1 print
~~~~~~~~~~~~
print参数处在列表上下文中

5.3.2 open
~~~~~~~~~~~
open操作符打开文件句柄
语法为
open 文件句柄,"文件名字符串"      --可以在文件名前添加<,>,>>代表r,w,a模式,跟shell类似,默认为r模式

open 文件句柄,"模式字符串","文件名"


  open DATAFILE "data.txt"    #  =open DATAFILE,"<","data.txt"
  open LOGFILE ">>log.txt"    #  =open LOGFILE,">>","log.txt"


5.3.3 对文件句柄进行输入输出
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
1. 输入操作:
<文件句柄>                                     --从文件句柄中行输入
print 文件句柄 内容                            --输出内容到文件句柄中
printf 文件句柄 格式字符串,填充值...             --注意文件句柄与内容之间+没有逗号+的!!
1. unlink 文件名                               --删除文件,注意:删除文件的权限跟文件本身的权限无关,而跟目录的权限有关
2. rename $oldName $newName
3. readlink $lnkFile              #返回符号链接指向的位置
4. chmod 模式 文件或目录
5. chown 拥有者,所属组,一系列文件    #这里的拥有者和所属组必须是数字形式的标识符,可以用getpwnam和getgrname函数将名字转换成数字
6. utime 新访问时间,新更改时间,文件列表   #修改文件的时间戳

5.3.4 对目录句柄进行输入输出
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
1. opendir
2. readdir                       #读出来的是该目录下的所有文件,但是只包含文件名
3. closedir
4. rmdir删除目录
5. mkdir 目录名,模式代码
6. rmdir 目录名                   #删除一个空目录

5.3.5 select:改变默认的文件句柄
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
默认情况下,print函数输出内容到STDOUT,可以用"select 文件句柄"的方式改变默认的文件句柄

5.3.6 hash变量的函数
~~~~~~~~~~~~~~~~~~~~~
1. each函数:遍历hash变量
while (($key,$value)=each %hash){
print $key=>$value";
}
2. exist函数:检查hash是否存在某个键
if(exists $books{"dina"}){
print "exist dina";
}
3. delete函数:从hash中删除指定的键值对
delete $books{$person};

5.3.7 split操作符根据分隔符拆开一个字符串
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
1. 用法为:
@fields=split /separatorPattern/, $string;#split会保留开头处的空字段,并省略结尾处的空字段
例如:@fields=splite /:/,":::a:b:c:::";#得到("","","","a","b","c")
2. split默认会以空白字符分割$_
3. 如果用复杂的模式分割,请避免在模式里用到捕获圆括号,这回启动所谓的"分隔保留模式"。在split里使用非捕获圆括号(?:),就可以安全进行分组

5.3.8 join函数将片段联合成一个字符串
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
1. 用法为
$result=join $glue,@fields;#join函数不是用模式

5.3.9 glob函数 #把通配符展开成相匹配的文件名
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
1. my @pm_files=glob "*.pm"  #会取得当前目录中所有pm为后缀的文件,但不包含以点号开头的文件
2. my @a_b_file=glob "*.a *.b" #可以一次匹配多个模式,在参数中用空格隔开各个模式
3. my @all_files=<*>           #glob函数可以简写成<*.pm>

5.3.10 字符串函数
~~~~~~~~~~~~~~~~~~
1. $where=index($big,$small[,$startPos]);  #从$big中找出$small首次位置,返回的位置从0算起,找不到则返回-1
2. rindex寻找子窜最后出现的位置
3. $part=substr($string,$initial_position[,$length]);   #起始位置可以为负,表示从字符串结尾开始倒数
                                                        #substr函数可以做为左值被=或者=~s///操作,改变$string的值!!
   $newStr=substr($string,$initial_position,$length,$replaceStr);  #返回将子串替换成$replaceStr后的$string
4. $str=sprintf(格式字符串,...)

5.3.11 sort函数
~~~~~~~~~~~~~~~~
1. sort [比较函数,]排序数组                               #比较函数中待比较的变量固定为$a与$b,且无需对$a,$b进行参数赋值,perl会自动完成
2. sort {...},排序数组                                   #若比较函数简单,则可以用代码块代替
3. <=>数字比较
4. cmp函数为默认的字符串比较
   

5.3.12 defined函数
~~~~~~~~~~~~~~~~~~~
    defined函数测试某个变量是否有值
    通过将值设为undef,使它成为未定义

5.3.13 undef函数
~~~~~~~~~~~~~~~~~
    undef(变量名) 取消定义变量

5.3.14 splice 删除、替换列表的切片 splice 列表 偏移位置 [长度[替代列表]]
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    偏移位置可以为负数,表示从结尾开始算的偏移位置、

5.3.15 grep 函数
~~~~~~~~~~~~~~~~~
    grep函数通过一个字符串列表搜索并返回一个与正则表达式匹配的字符串数组
    grep /正则表达式/,列表

5.3.16 map函数
~~~~~~~~~~~~~~~
    1. map函数的一般形式为:
       map 表达式 数组
       其中表达式为相对数组中的每个元素进行重复的表达式


  %hash=map( ($_=>1),@user_array)
  #若@user_array中的元素为"sam","joe","kim",则map扩展为("sam"=>1,"joe"=>1,"kim"=>1)

5.3.17 delete函数
~~~~~~~~~~~~~~~~~~
    delete ($hash{key});
    从散列中删除元素,不能简单的把散列元素赋值为undef,而需要调用delete函数

5.3.18 读取二进制文件的函数
~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    1. binmode函数   #指定打开文件句柄为二进制流模式
       binmode 文件句柄
    2. read函数      #读取二进制流
       read 文件句柄 保存数据的缓冲(一般为标量) 要读取的字节数
       #perl的字符没有结束符,它可以包含任何字符,这就使得perl的字符串可以保存二进制数据
    3. unpack函数    #解包二进制数据,并将它转换成值的数组
       @列表变量=unpack 解码模式 $二进制标量
       其中解码模式指定需要转换为的格式,说明为
       b          :二进制数
       H          :十六进制
       a          :ASCII字符
       


  #想将缓冲作为一系列两个数字的十六进制数则使用模板"H2"
  my @hex=unpack("H2",$buffer);

6 模块
-------

6.1 require "dumpvar.pl";
==========================
   1. dumpValue(变量引用)    #打印出复杂的数据结构

6.2 use Storable;
==================
   1. dclone(变量引用)       #克隆一个复杂的数据结构,生成一个所有引用的拷贝
      若变量中还含有引用,则也会克隆一份引用所指变量拷贝,也就是深度拷贝

7 高级专题
-----------

7.1 正则表达式
===============

7.1.1 不捕获模式
~~~~~~~~~~~~~~~~~
需要在左括号的后面加上?:以告知perl这一对括号完全是为了分组而存在的。
/(?:xxx)yyyzzz/;

7.1.2 命名捕获(use 5.010;)
~~~~~~~~~~~~~~~~~~~~~~~~~~~
捕获的结果会进入一个特殊的hash%+,为捕获串加标签的方法是(?<命名>模式)这样的写法。
抽取值时使用$+{命名}来获得值
反向引用时使用\g{命名}的方法或者\k<命名>的方法来在正则表达式中反向引用之前匹配的值

7.1.3 \U,\L,\E
~~~~~~~~~~~~~~~
1. \U...\E将\U到\E之间的字符串转换成大写
2. \L...\E将\L到\E之间的字符串转换成小写
3. 可以用于perl的字符串中

7.1.4 \u.\l
~~~~~~~~~~~~
1. \u将后面一个字符变成大写
2. \l将后面一个字符变成小写
3. 可以用于perl的字符串中

7.1.5 非贪婪量词
~~~~~~~~~~~~~~~~~
    正则表达式一般都是贪婪匹配的,然后可以在量词后面加上一个问号来表示非贪婪匹配


  /.*?:/  #停止在第一个冒号而不是最后一个处
  例如:
  .+?
  (5,10)?
  ??

7.1.6 锚点(anchor)允许你限制模式能在什么地方匹配。
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    \b匹配单词边界
    

7.2 用inline模板结合C与perl
============================

7.2.1 Perl调用C
~~~~~~~~~~~~~~~~
    l. 例子:


  use strict;
  use warnings;
  use Inline "C";
  sub say_hello();
  say_hello();
  __END__
  __C__
  void say_hello(){
      printf("Hello world\n");
      }

    2. 解析
       1. 程序开始时告诉perl你想包含一些内联C代码
          use Inline "C"
       2. 后面是函数say_hello的perl原型
          sub say_hello();
       3. 关键字__END__用于告诉perl已经到达了程序的结尾
       4. __C__,告诉Inline模块后面是C代码
       5. 后面是C函数本身,注意,这里的C解析器不是完整的解析器,在某方面有受限制
    3. C返回perl的数组和散列
       要用C返回perl的数组和散列,必须直接操纵perl参数堆栈
       1. 返回数组
          int x,y                #定义局部变量声明,这些声明为数组的内容
          Inline_Stack_Vars;     #用宏Inline_Stack_Vars声明变量来跟踪堆栈的行为
          Inline_Stack_Rest;     #清除旧的堆栈信息
          Inline_Stack_Push(newSViv(x));   #x,y为整数,需要调用函数newSViv(new scalar value(SV) from integer value(iv))转换为perl标量
                                           #用宏Inline_Stack_Push将标量推入堆栈
          Inline_Stack_Done;     #告诉系统,完成了堆栈的工作

7.2.2 C调用Perl
~~~~~~~~~~~~~~~~
    可以使用eval_pv函数执行任何perl命令,例如
    eval_pv("main::handle_error('message')",0);   #调用perl函数handler_error,返回的结果为一个*SV
    SV为perl中变量的结构:
    struct sv{
      void * sv_any;    /*某对象指针*/
      U32    sv_refcnt; /*对少引用*/
      U32    sv_flags;  /*标志,用于处理变量类型信息和注册信息*/

7.3 perl的面向对象编程
=======================
   1. 对象
      包中返回的数据结构,使用bless函数处理后,会自动记住自己的包名,就可以类似对象一样直接调用包中定义的方法
   2. 使用对象的方式调用函数时,perl自动将第一个参数用自己带入
      perl中,一切都是公有的,根本不存在访问保护。
   3. 继承
      perl中使用@ISA数组实现继承的作用,perl寻找方法时,它首先在被调用的包中寻找,然后搜索通过@ISA数组指定的包。
      需要注意的是,只有用对象的方式调用时才会去@ISA中寻找,若直接调用某个方法,就不会发挥作用
   4. 运算符重载
      使用overload包来定义运算符重载,例如


  use overload{
       '+'=>\&add,
       '-'=>\&substract,
       '"'=>\&to_string
    };

   5. 例如


  use strict;
  use warnings;
  package time_hash;
  sub new($$)
  {
  my ($hours,$minutes)=@_;
  my $self={};
  $self->{hours}=$hours;
  $self->{minutes}=$minutes;
  return (bless $self)                  #bless说明为面向对象
  #return ($self)
  }
 
  sub add(\%\%)
  {
  my ($self,$other)=@_;
  $self->{hours}+=$other->{hours};
  $self->{minutes}+=$other->{minutes};
  $self->{hours}+=int($self->{minutes}/60);
  $self->{minutes}%=60;
  }
 
  sub subtract($$)
  {
  my $self=shift;
  my $other=shift;
  $self->{hours}-=$other->{hours};
  $self->{minutes}-=$other->{minutes};
  while ($self->{minutes}<0){
    $self->{minutes}+=60;
    $self->{hours}--;
    }
  }
 
  sub to_string(\%)
  {
  my $self=shift;
  return(sprintf("%d:%02d",$self->{hours},$self->{minutes}));
  }
 
  my $time1=&new(1,10);
  my $time2=&new(2,20);
  $time1->add($time2);
  print "time1=",$time1->to_string;
  print "time2=",$time2->to_string;

8 语言特性
-----------
  1. 变量在不同上下文环境中表示不同意义
  2. 子例程和格式声明都是全局声明,而不管你把它们放在哪里
  3. 由于声明只在编译时起作用,故它们对语句的主要执行顺序没有影响,这意味着你不能做有条件的子例程或格式声明
  4. 列表赋值,在逻辑上并行发生,因此可以


  ($a,$b)=($b,$a);

  5. 数组时有序的,散列是无序的
  6. 赋值语句返回实际的变量作为左值,因此可以在同一个语句中多次改变同一个变量的值


  ($tmp-=32)*=5/16;
  #$tmp==-10;

  7. perl提供了<=>比较符,相等时为0,大于时为1,小于时为-1
  8. 什么是真
     除了""和"0",所有字符串为真,包括" "
     除了0外,所有数字为真
     所有引用为真
     所有未定义的值为假
  9. 在perl中,if|while等语句中的大括号是必须得。而C中,如果只有一句语句,那么可以省略大括号
  10. if...elsif语句,而不是if...elseif语句
  11. 有unless...但是没有elsunless语句
  12. 行输入操作符在字符串最后并不去掉换行符,因此空白行的值是"\n",并且该值为真
  13. 行输入操作符在文件结尾的时候,返回未定义值,并且改值为假
  14. 在标量环境中使用数组,就会返回数组的长度


  while(@ARGV){
  process(shift @ARGV);
  }

  15. 正则表达式一般都是贪婪匹配的,然后可以在量词后面加上一个问号来表示非贪婪匹配


  /.*?:/  #停止在第一个冒号而不是最后一个处

  16. perl的注释方式
      1. 单行注释以#开头
  17. pod :
      1. 注释
         语句的任何地方存在以=pod开头的行都是合法的,perl将忽略从这一行开始直到下一个由=cut开头的行


  =pod
  this
  is
  zhushi
  =cut

         被忽略的行被认为是pod(plain old document),可以有一个程序从perl模块中抽取pod注释
      2. NAME部分    #给程序的名字以及对它的作用所作的一行简短描述
         =head1 NAME
      3. SYNOPSIS部分  #列出了程序名字以及所有选项和可以给它传递的其他参数
         =head1 SYNOPSIS
      4. DESCRIPTION部分   #对程序作用的描述
         =head1 DESCRIPTION
      5. OPTIONS部分       #选项列表的文档
         =head1 OPTIONS    #OPTIONS部分开始
         =over 列表的缩进空格数
         =item 文本说明
         =back      #列表结束
      6. SEE ALSO部分      #提供一个推荐阅读列表
         =head1 SEE ALSO
         L<链接文本>
  18. 与shell程序员预期的相反,在双引号里面的反引号不做内插,在双引号里面的单引号也不会阻止变量计算。
  19. 与shell一样,perl也支持here-document,语法跟shell一样


  print <<EOF;
  类似print "string";
  EOF
  print <<"EOF";
  类似print "string";
  EOF
  print <<"EOF" x 10;
  打印会重复10次
  EOF
  print <<'EOF';
  类似print 'string';
  EOF
  print <<`EOF`;
  类似print `string`;      #执行命令
  EOF
  #注意别忘了在最后放分号以结束语句
  #甚至可以用here-document填充一个数组
  @sauces=<<End_Lines=~m/(\S.*\S)/g;
      normal tomato
      spicy tomato
      green chile
      pesto
      white wine
  End_Lines

  20. perl只有标量环境和列表环境,没有散列环境!标量环境又分为字符串环境、数字环境和无所谓环境(如布尔环境、空环境)
  21. 除了双引号,反引号操作符qx,模式匹配操作符m//,替换操作符s///和正则表达式操作符qr//都会做内插动作
  22. use算作BEGIN块,故使用use什么引入声明和定义时,它可以在编译时就require各模块
  23. 与C不一样,@ARGV第一个参数不是程序的名称

本文出自 “暗日” 博客,请务必保留此出处http://darksun.blog.51cto.com/3874064/972536

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值