Perl 学习

目录

chop与chomp的区别

  • chop()函数,只是去除最后一个字符
  • chomp()函数,就要首先判断最后一个字符是不是为"\n",他才去除。
  • 对于没有赋初值的scaler,默认初始为空,但若参与运算,则当作0处理。

    $x = $ff + 1;
    print("$x\n");
    print("$ff\n");
    

    这里没有对ff定义,但x的值print出来是1,说明ff在参与运算时是0;但运算后其值并没有改变,还是空。

    codes to comment

    正则匹配注意事项

  • =~ 匹配时,等号和~符号之间不能有空格!,否则输出一串怪异数字。
  • lc和uc

    $side = uc $attrs[0];  把attrs[0]转换成大写,然后给side变量赋值。
    $gender = lc $attrs[1]; 把attrs[1]转换成小写,然后给gender赋值。
    

    split 产生空元素

    在按照/ /或者/\s+/来split字符串时,常会遇到莫名其妙多出来一个空元素的问题。

    这是因为如果字符串开头就是空格,split会把开头的前导空白符(一个空字符)也算作一个元素。

    如果要按照空格来split,有几种方法:

  • split ' '或者直接用默认形式split,不加任何东西
  • split ' '是split的特殊情况,该格式是模拟awk的默认行为,所以在分割行为开始之前,会把字符串中的前导空格全部删除,然后再使用split /\s+/处理。
  • 删除前导空白符,再用split(/\s+/,$_);
  • $_ =~ s/^\s+//; ## 丢弃前导空白符 $_ =~ s/\s+$//; ## 丢弃末尾空白符
  • 1. 运行perl

  • 文件顶部加 #!/usr/bin/perl
  • 加权限 chmod u+x file.pl 或者chmod 0755 file.pl
  • ./file.pl
  • 2. 字符串

    字符串连接符

    $str = "hello" . "world";       # 字符串连接
    $num = 5 + 10;                  # 两数相加
    $mix = $str . $num;             # 连接字符串和数字
    
  • qq(string in qq):相当于”string in qq”
  • q(string in q): 相当于’string in q’
  • ( )可换为<>,{ },[ ]等配对字符 qq{string in qq};
  • here文档

    #!/usr/bin/perl
    $a = 10;
    $var = <<"EOF";
    这是一个 Here 文档实例,使用双引号。
    可以在这输如字符串和变量。
    例如:a = $a
    print "$var\n";
    
    这是一个 Here 文档实例,使用双引号。
    可以在这输如字符串和变量。
    例如:a = 10
    

    $a=<< “EOF” 的意思就是说:下一行开始,直到遇见“EOF”为止,所有的字符都按照指定的格式存入变量a中。你可以用EEE,MAMA等等其他的名字都可以。

    多行字符串

    #!/usr/bin/perl
    $string = '
        —— 学的不仅是技术,更是梦想!
    print "$string\n";
    

    也可以用here文档

    # __FILE__, __LINE__, 和 __PACKAGE__ 分别表示当前执行脚本的文件名,行号,包名
    文件名 test.pl
    包名 main
    

    v 字符串

    一个以 v 开头,后面跟着一个或多个用句点分隔的整数,会被当作一个字串文本。将整数转换为对应的ASCII码字符。

    $foo    = v102.111.111; # 代表foo
    $martin = v77.97.114.116.105.110; # 代表Martin
    

    3. 变量

    标量:$myfirst=123; 

    数组:@arr=(1,2,3) ,索引用$arr[0]

    哈希:%h=('a'=>1,'b'=>2); 索引用$h{'a'}

  • 整形:$x = 12345; 实际是浮点数的特例
  • 8 进制和 16 进制数:8 进制以 0 开始,16 进制以 0x 开始。
  • 浮点数:11.4 、 -0.3 、.3 、 3. 、 54.1e+02 、 5.41e03。

  • 浮点寄存器通常不能精确地存贮浮点数,从而产生误差,在运算和比较中要特别注意。指数的范围通常为 -309 到 +308
  • 字符串: 见上面

    变量上下文

    Perl 解释器会根据上下文来决定变量的类型。实例如下:

    #!/usr/bin/perl
    @names = ('google', 'runoob', 'taobao');
    @copy = @names;   # 复制数组
    $size = @names;   # 数组赋值给标量,返回数组元素个数
    
    创建数组:括号或者qw
    @array = (1, 2, 'Hello');
    @array = qw/这是 一个 数组/;
    @days = qw/google #qw支持多行定义数组
    taobao
    runoob/;
    # 可以按索引给数组赋值
    $array[6] = 'Sunday'; # 允许索引超出定义的长度
    
    数组序列号
    @var_10 = (1..10);
    @var_20 = (10..20);
    @var_abc = (a..z);
    print "@var_10\n";   # 输出 1 到 10
    print "@var_20\n";   # 输出 10 到 20
    print "@var_abc\n";  # 输出 a 到 z
    

    $size = @array;

    返回的是数组长度,不是元素个数。

    添加和删除数组元素
    类型和描述 @sites = ("google","runoob","taobao"); $new_size = @sites ; print "1. \@sites = @sites\n"."原数组长度 :$new_size\n"; # 在数组结尾添加一个元素 $new_size = push(@sites, "baidu"); print "2. \@sites = @sites\n"."新数组长度 :$new_size\n"; # 在数组开头添加一个元素 $new_size = unshift(@sites, "weibo"); print "3. \@sites = @sites\n"."新数组长度 :$new_size\n"; # 删除数组末尾的元素 $new_byte = pop(@sites); print "4. \@sites = @sites\n"."弹出元素为 :$new_byte\n"; # 移除数组开头的元素 $new_byte = shift(@sites); print "5. \@sites = @sites\n"."弹出元素为 :$new_byte\n";
    #!/usr/bin/perl
    @sites = qw/google taobao runoob weibo qq facebook 网易/;
    @sites2 = @sites[3,4,5];
    # 输出:weibo qq facebook
    # 连续索引也可以用..:
    @sites2 = @sites[3..5];
    
    替换数组元素

    Perl 中数组元素替换使用 splice() 函数:

    splice @ARRAY, OFFSET [ , LENGTH [ , LIST ] ]

    @nums = (1..20);
    print "替换前 - @nums\n";
    #从第6个元素开始替换数组中的5个元素:
    splice(@nums, 5, 5, 21..25); 
    print "替换后 - @nums\n";
    #替换前 - 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
    #替换后 - 1 2 3 4 5 21 22 23 24 25 11 12 13 14 15 16 17 18 19 20
    
    将字符串转换为数组

    split [ PATTERN [ , EXPR [ , LIMIT ] ] ]

  • PATTERN:分隔符,默认为空格。
  • EXPR:指定字符串数。
  • LIMIT:如果指定该参数,则返回该数组的元素个数。
  • # 定义字符串
    $var_test = "runoob";
    $var_string = "www-runoob-com";
    $var_names = "google,taobao,runoob,weibo";
    # 字符串转为数组
    @test = split('', $var_test);
    @string = split('-', $var_string);
    @names  = split(',', $var_names);
    print "$test[3]\n";  # 输出 o
    print "$string[2]\n";  # 输出 com
    print "$names[3]\n";   # 输出 weibo
    
    将数组转换为字符串

    Perl 中将数组转换为字符串使用 join() 函数,语法格式如下:

  • join EXPR, LIST
  • # 数组转为字符串
    $string1 = join( '-', @string );
    $string2 = join( ',', @names );
    

    Perl 中数组排序使用 sort() 函数,语法格式如下:

  • sort [ SUBROUTINE ] LIST
  • # 定义数组
    @sites = qw(google taobao runoob facebook);
    print "排序前: @sites\n";
    # 对数组进行排序
    @sites = sort(@sites);
    # 排序后: facebook google runoob taobao
    
    特殊变量: $[

    特殊变量 \([** 表示数组的第一索引值,一般都为 0 ,如果我们将 **\)[ 设置为 1,则数组的第一个索引值即为 1,第二个为 2,以此类推。不推荐,新版中已经被废弃

    @numbers = (1,3,(4,5,6)); 
    print "numbers = @numbers\n"; #numbers = 1 3 4 5 6
    
    创建hash

    $data{'google'} = 'google.com';

    通过列表设置, 列表中第一个元素为 key,第二个为 value。

    %data = ('google', 'google.com', 'runoob', 'runoob.com', 'taobao', 'taobao.com');
    
    %data = ('google'=>'google.com', 'runoob'=>'runoob.com', 'taobao'=>'taobao.com');
    

    或者用-代替'':

    %data = (-google=>'google.com', -runoob=>'runoob.com', -taobao=>'taobao.com');
    

    但这种方式的key不能出现空格,读取时:

    $val = $data{-google}
    $val = $data{-runoob}
    
    读取哈希值

    @array = @data{-taobao, -runoob};

    读取所有key

    @names = keys %data;

    读取所有value

    @urls = values %data;

    检测元素是否存在

    如果你在哈希中读取不存在的 key/value 对 ,会返回 undefined 值,且在执行时会有警告提醒。为了避免这种情况,我们可以使用 exists 函数来判断key是否存在

    if( exists($data{'facebook'} ) ){}
    else{}
    
    哈希中添加或删除元素
    # 添加元素
    $data{'facebook'} = 'facebook.com';
    # 删除哈希中的元素
    delete $data{'taobao'};
    

    4. 条件

    if() {} elsif {} else {}

    use Switch;
    $var = 10;
    @array = (10, 20, 30);
    %hash = ('key1' => 10, 'key2' => 20);
    switch($var){
       case 10    { print "数字 10\n" }
       case "a"   { print "字符串 a" }
       case [1..10] { print "数字在列表中" }
       case (\@array){ print "数字在数组中" }
       case (\%hash) { print "在哈希中" }
       else        { print "没有匹配的条件" }
    

    其中@array 和%hash可以判断var的值是否在列表或者hash内。

    另外,还可以在case中加上next, case还会匹配下面其他的是否满足:

    2. case 10    { print "数字 10\n"; next; }  # 匹配后继续执行
    

    三元运算符

    Exp1 ? Exp2 : Exp3;

    $status = ($favorite > 60 )? "热门网站" : "不是热门网站";
    

    5. 循环

    while () {}

    条件为真时循环

    until () {}

    条件为假时循环

    for( ; ; )

    for( $a = 0; $a < 10; $a = $a + 1 ){
        print "a 的值为: $a\n";
    

    foreach

    循环列表或者集合变量值

    @list = (2, 12, 36, 42, 51);
    # 执行foreach 循环
    foreach $a (@list){
        print "a 的值为: $a\n";
    

    do...while...

    statement(s); }while( condition );

    next 语句用于停止执行从next语句的下一语句开始到循环体结束标识符之间的语句,转去执行continue语句块,然后再返回到循环体的起始处开始执行下一次循环。

    $a = 10;
    while( $a < 20 ){
       if( $a == 15)
           # 跳出迭代
           $a = $a + 1;
           next;
       print "a 的值为: $a\n";
       $a = $a + 1;
    # 输出结果会跳过15
    

    Perl last 语句用于退出循环语句块,从而结束循环,last语句之后的语句不再执行,continue语句块也不再执行。

    continue

    Perl continue 块通常在条件语句再次判断前执行。continue 语句可用在 while 和 foreach 循环中。

    $a = 0;
    while($a < 3){
       print "a = $a\n";
    }continue{
       $a = $a + 1;
    a = 0
    a = 1
    a = 2
    @list = (1, 2, 3, 4, 5);
    foreach $a (@list){
       print "a = $a\n";
    }continue{
       last if $a == 4;
    a = 1
    a = 2
    a = 3
    a = 4
    

    Perl redo 语句直接转到循环体的第一行开始重复执行本次循环,redo语句之后的语句不再执行,continue语句块也不再执行。

    $a = 0;
    while($a < 10){
       if( $a == 5 ){
          $a = $a + 1;
          redo;
       print "a = $a\n";
    }continue{
       $a = $a + 1;
    a = 0
    a = 1
    a = 2
    a = 3
    a = 4
    a = 6
    a = 7
    a = 8
    a = 9
    

    Perl 有三种 goto 形式:got LABLE,goto EXPR,和 goto &NAME.

    goto label:

    $a = 10;
    LOOP:do
        if( $a == 15){
           # 跳过迭代
           $a = $a + 1;
           # 使用 goto LABEL 形式
           print "跳出输出 \n";
           goto LOOP;
           print "这一句不会被执行 \n";
        print "a = $a\n";
        $a = $a + 1;
    }while( $a < 20 );
    

    goto expr:

    $a = 10;
    $str1 = "LO";
    $str2 = "OP";
    LOOP:do
        if( $a == 15){
           # 跳过迭代
           $a = $a + 1;
           # 使用 goto EXPR 形式
           goto $str1.$str2;    # 类似 goto LOOP
        print "a = $a\n";
        $a = $a + 1;
    }while( $a < 20 );
    

    6. 运算符

    基本运算符

    数字的比较: $a=10,$b=20

    @months = qw( 一月 二月 三月 四月 五月 六月 七月 八月 九月 十月 十一月 十二月 );
    @days = qw(星期天 星期一 星期二 星期三 星期四 星期五 星期六);
    ($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst) = localtime();
    print "$mday $months[$mon] $days[$wday]\n";
    12 六月 星期天
    
    $datestring = localtime();
    print "时间日期为:$datestring\n";
    时间日期为:Sun Jun 12 11:27:31 2016
    

    求运行时间

    新纪元时间(Epoch Time)

    我们可以使用 time() 函数来获取新纪元时间,该函数返回从1970年1月1日起累计的秒数。

    一般可以用来求程序运行的时间。

    $epoc = time();
    $epoc1 = time();
    $run_time = $epoc1-$epoc;
    

    POSIX 函数 strftime()

    函数 strftime() 可以将时间格式化为我们想要的格式。

    use POSIX qw(strftime);
    $datestring = strftime "%Y-%m-%d %H:%M:%S", localtime;
    printf("时间日期 - $datestring\n");
    #  GMT 格式化时间日期
    $datestring = strftime "%Y-%m-%d %H:%M:%S", gmtime;
    printf("时间日期 - $datestring\n");
    
    时间日期 - 2016-06-12 12:15:13
    时间日期 - 2016-06-12 04:15:13
    

    8. 子程序(函数)

    子程序传参

    Perl 子程序可以和其他编程一样接受多个参数,子程序参数使用特殊数组 @_ 标明。因此子程序第一个参数为 $_[0], 第二个参数为 ​$_[1], 以此类推。

    # 定义求平均值函数 sub Average{ # 获取所有传入的参数 $n = scalar(@_); $sum = 0; foreach $item (@_){ $sum += $item; $average = $sum / $n; print '传入的参数为 : ',"@_\n"; # 打印整个数组 print "第一个参数值为 : $_[0]\n"; # 打印第一个参数 print "传入参数的平均值为 : $average\n"; # 打印平均值 # 调用函数 Average(10, 20, 30);

    向函数传递列表

    # 定义函数
    sub PrintList{
       my @list = @_;
       print "列表为 : @list\n";
    $a = 10;
    @b = (1, 2, 3, 4);
    # 列表参数
    PrintList($a, @b);
    
    列表为 : 10 1 2 3 4
    

    相函数传递哈希

    # 方法定义
    sub PrintHash{
       my (%hash) = @_;
       foreach my $key ( keys %hash ){
          my $value = $hash{$key};
          print "$key : $value\n";
    %hash = ('name' => 'runoob', 'age' => 3);
    # 传递哈希
    PrintHash(%hash);
    

    子程序返回值

    如果没有使用 return 语句,则子程序的最后一行语句将作为返回值。

    # 方法定义
    sub add_a_b{
       # 不使用 return
       $_[0]+$_[1];  
       # 使用 return
       # return $_[0]+$_[1];  
    print add_a_b(1, 2)
    

    子程序的私有变量

    默认情况下,Perl 中所有的变量都是全局变量,这就是说变量在程序的任何地方都可以调用。如果我们需要设置私有变量,可以使用 my 操作符来设置。

    my 操作符用于创建词法作用域变量,通过 my 创建的变量,存活于声明开始的地方,直到闭合作用域的结尾。

    闭合作用域指的可以是一对花括号中的区域,可以是一个文件,也可以是一个 if, while, for, foreach, eval字符串。

    # 全局变量
    $string = "Hello, World!";
    # 函数定义
    sub PrintHello{
       # PrintHello 函数的私有变量
       my $string;
       $string = "Hello, Runoob!";
       print "函数内字符串:$string\n";
    # 调用函数
    PrintHello();
    print "函数外字符串:$string\n";
    
    函数内字符串:Hello, Runoob!
    函数外字符串:Hello, World!
    

    变量的临时赋值

    我们可以使用 local 为全局变量提供临时的值,在退出作用域后将原来的值还回去。local 定义的变量不存在于主程序中,但存在于该子程序和该子程序调用的子程序中。定义时可以给其赋值

    # 全局变量
    $string = "Hello, World!";
    sub PrintRunoob{
       # PrintHello 函数私有变量
       local $string;
       $string = "Hello, Runoob!";
       # 子程序调用的子程序
       PrintMe();
       print "PrintRunoob 函数内字符串值:$string\n";
    sub PrintMe{
       print "PrintMe 函数内字符串值:$string\n";
    sub PrintHello{
       print "PrintHello 函数内字符串值:$string\n";
    # 函数调用
    PrintRunoob();
    PrintHello();
    print "函数外部字符串值:$string\n";
    
    PrintMe 函数内字符串值:Hello, Runoob!
    PrintRunoob 函数内字符串值:Hello, Runoob!
    PrintHello 函数内字符串值:Hello, World!
    函数外部字符串值:Hello, World!
    
    use feature 'state';
    sub PrintCount{
       state $count = 0; # 初始化变量
       print "counter 值为:$count\n";
       $count++;
    for (1..5){
       PrintCount();
    
    counter 值为:0
    counter 值为:1
    counter 值为:2
    counter 值为:3
    counter 值为:4
    

    注1:state仅能创建闭合作用域为子程序内部的变量。

    注2:state是从Perl 5.9.4开始引入的,所以使用前必须加上 use。

    注3:state可以声明标量、数组、哈希。但在声明数组和哈希时,不能对其初始化(至少Perl 5.14不支持)。

    子程序调用上下文

    子程序调用过程中,会根据上下文来返回不同类型的值,比如以下 localtime() 子程序,在标量上下文返回字符串,在列表上下文返回列表:

    # 标量上下文
    my $datestring = localtime( time );
    print $datestring;
    print "\n";
    # 列表上下文
    ($sec,$min,$hour,$mday,$mon, $year,$wday,$yday,$isdst) = localtime(time);
    printf("%d-%d-%d %d:%d:%d",$year+1990,$mon+1,$mday,$hour,$min,$sec);
    print "\n";
    
    Sun Jun 12 15:58:09 2016
    2106-6-12 15:58:9
    

    my 和 local 的区别

    内部 -> 外部:

  • (1)my 和 local 都只在一个 block 里有效,出去就失效;
  • (2)但是 local 的变量可以继续在这个 block 中调用的子程序中存在;
  • (3)如果有与外界同名的变量,两者在 block 退出后都不影响外界同名变量;
  • 外部 -> 内部:

    (1)外部设置 my、local、缺省均队内有效,但是同名变量外部 my,在 block 内部 local 是不允许的。因为二者在 block 中调用的子程序中均有效,会冲突。

    (2)如果在一个 block 中有一个 my 修饰的变量和外界的一个变量同名,而且又需要在这个 block 中使用外界变量时,两个办法:

  • 第一个办法,用 main 的 package 修饰这个变量名 $main::global。
  • 第二个办法,用 our 修饰 our $global,那么该 block 中接下来出现的所有 $global 都是外界的 global。
  • (3)编写脚本时,注意作用域,防止外部影响内部。

    9. 引用

    引用就是指针,Perl 引用是一个标量类型可以指向变量、数组、哈希表(也叫关联数组)甚至子程序,可以应用在程序的任何地方。

    定义变量的时候,在变量名前面加个\,就得到了这个变量的一个引用

    $scalarref = \$foo;     # 标量变量引用
    $arrayref  = \@ARGV;    # 列表的引用
    $hashref   = \%ENV;     # 哈希的引用
    $coderef   = \&handler; # 子过程引用
    $globref   = \*foo;     # GLOB句柄引用
    

    在数组中我们可以用匿名数组引用,使用 [] 定义:

    $aref= [ 1,"foo",undef,13 ];
    

    匿名数组的元素仍然可以是匿名数组,所以我们可以用这种方法构造数组的数组,可以构造任意维度的数组。

    my $aref = [
            [1, 2, 3],
            [4, 5, 6],
            [7, 8, 9],
    

    访问的时候用引用访问:

    $aref->[0]->[0] 或者

    $aref->[0][0]"

    哈希中我们可以用匿名哈希引用,使用 {} 定义:

    $href= { APR =>4, AUG =>8 };
    

    我们也可以创建一个没有子程序名的匿名子程序引用:

    $coderef = sub { print "Runoob!\n" };
    

    取消引用可以根据不同的类型使用 $, @ 或 % 来取消,实例如下:

    $var = 10;
    # $r 引用 $var 标量
    $r = \$var;
    # 输出本地存储的 $r 的变量值
    print "$var 为 : ", $$r, "\n";
    @var = (1, 2, 3);
    # $r 引用  @var 数组
    $r = \@var;
    # 输出本地存储的 $r 的变量值
    print "@var 为: ",  @$r, "\n";
    %var = ('key1' => 10, 'key2' => 20);
    # $r 引用  %var 数组
    $r = \%var;
    # 输出本地存储的 $r 的变量值
    print "\%var 为 : ", %$r, "\n";
    
    10 为 : 10
    1 2 3 为: 123
    \%var 为 : key110key220
    

    判断变量类型

    ref 来判断: ref($r)

    函数引用格式: &

    调用引用函数格式: & + 创建的引用名。

    # 函数定义
    sub PrintHash{
       my (%hash) = @_;
       foreach $item (%hash){
          print "元素 : $item\n";
    %hash = ('name' => 'runoob', 'age' => 3);
    # 创建函数的引用
    $cref = \&PrintHash;
    # 使用引用调用函数
    &$cref(%hash);
    

    10. 格式化输出

    Perl 中可以使用 format 来定义一个模板,然后使用 write 按指定模板输出数据。

    format FormatName =
    fieldline
    value_one, value_two, value_three
    fieldline
    value_one, value_two
    

    参数解析:

  • FormatName :格式化名称。
  • fieldline :一个格式行,用来定义一个输出行的格式,类似 @,^,<,>,| 这样的字符。
  • value_one,value_two…… :数据行,用来向前面的格式行中插入值,都是perl的变量。
  • . :结束符号。
  • $text = "google runoob taobao";
    format STDOUT =
    first: ^<<<<<  # 左边对齐,字符长度为6
        $text
    second: ^<<<<< # 左边对齐,字符长度为6
        $text
    third: ^<<<< # 左边对齐,字符长度为5,taobao 最后一个 o 被截断
        $text  
    write
    
    first: google
    second: runoob
    third: taoba
    
  • 格式行以 @ 或者 ^ 开头,这些行不作任何形式的变量代换。
  • @ 字段(不要同数组符号 @ 相混淆)是普通的字段。
  • @,^ 后的 <, >,| 长度决定了字段的长度,如果变量超出定义的长度,那么它将被截断。
  • <, >,| 还分别表示,左对齐,右对齐,居中对齐。
  • ^ 字段用于多行文本块填充。
  • =================================== =================================== Runoob 30 2500.00 =================================== =================================== Jaffer 40 4000.00 ===================================
  • $~ ($FORMAT_NAME) :格式名字 \(^ (\)FORMAT_TOP_NAME) :当前的表头格式名字存储在
  • $% ($FORMAT_PAGE_NUMBER) :当前输出的页号
  • $= ($FORMAT_LINES_PER_PAGE) :每页中的行数
  • $| ($FORMAT_AUTOFLUSH) :是否自动刷新输出缓冲区存储
  • $^L ($FORMAT_FORMFEED) :在每一页(除了第一页)表头之前需要输出的字符串存储在
  • $~ = "MYFORMAT"; # 指定默认文件变量下所使用的格式
    write;           # 输出 $~ 所指定的格式
    format MYFORMAT = # 定义格式 MYFORMAT 
    =================================
          Text # 菜鸟教程
    =================================
    write;
    
    =================================
          Text # 菜鸟教程
    =================================
    =================================
          Text # 菜鸟教程
    =================================
    

    如果不指定$~的情况下,会输出名为STDOUT的格式:

    write;         # 不指定$~的情况下会寻找名为STDOUT的格式
    format STDOUT =
    ~用~号指定的文字不会被输出
    ----------------
      STDOUT格式
    ----------------
    

    如果STDOUT也没有,会报错。

    此外我们通过添加报表头部信息来演示 $^ 或 $FORMAT_TOP_NAME 变量的使用

    format EMPLOYEE =
    ===================================
    $name, $age
    @#####.##
    $salary
    ===================================
    format EMPLOYEE_TOP =
    ===================================
    Name                    Age
    ===================================
    select(STDOUT);
    $~ = EMPLOYEE;
    $^ = EMPLOYEE_TOP;
    @n = ("Ali", "Runoob", "Jaffer");
    @a  = (20,30, 40);
    @s = (2000.00, 2500.00, 4000.000);
    $i = 0;
    foreach (@n){
       $name = $_;
       $age = $a[$i];
       $salary = $s[$i++];
       write;
    
    ===================================
    Name                    Age
    ===================================
    ===================================
    Ali                     20
      2000.00
    ===================================
    ===================================
    Runoob                  30
      2500.00
    ===================================
    ===================================
    Jaffer                  40
      4000.00
    ===================================
    

    也可以使用 $% 或$FORMAT_PAGE_NUMBER 为报表设置分页:

    # 添加分页 $% 
    format EMPLOYEE_TOP =
    ===================================
    Name                    Age Page @<
    =================================== 
    
    ===================================
    Name                    Age Page 1
    ===================================
    

    输出到文件

    默认情况下函数write将结果输出到标准输出文件STDOUT,我们也可以使它将结果输出到任意其它的文件中。最简单的方法就是把文件变量作为参数传递给write,如:

    write(MYFILE);
    

    但是这样就不能用$~变量来改变所使用的打印格式。系统变量$~只对默认文件变量起作用,

    if (open(MYFILE, ">tmp")) {
    $~ = "MYFORMAT";
    write MYFILE; # 含文件变量的输出,此时会打印与变量同名的格式,即MYFILE。$~里指定的值被忽略。
    format MYFILE = # 与文件变量同名 
    =================================
          输入到文件中
    =================================
    close MYFILE;
    

    我们可以使用select改变默认文件变量时,它返回当前默认文件变量的内部表示,这样我们就可以创建子程序,按自己的想法输出,又不影响程序的其它部分。

    if (open(MYFILE, ">>tmp")) {
    select (MYFILE); # 使得默认文件变量的打印输出到MYFILE中
    $~ = "OTHER";
    write;           # 默认文件变量,打印到select指定的文件中,必使用$~指定的格式 OTHER
    format OTHER =
    =================================
      使用定义的格式输入到文件中
    =================================
    close MYFILE;
    

    11. 文件操作

    open(DATA, "<file.txt") or die "file.txt 文件无法打开, $!";
    while(<DATA>){
       print "$_";
    

    <表示只读方式。

    sysopen 函数类似于 open 函数,只是它们的参数形式不一样。

    <FILEHANDL> 操作符

    我们使用 <FILEHANDLE> 操作符时,它会返回文件句柄中每一行的列表,例如我们可以导入所有的行到数组中。

    读取 import.txt 并将每一行放到 @lines 数组中:

    open(DATA,"<import.txt") or die "无法打开数据";
    @lines = <DATA>; #<>操作符
    print @lines;    # 输出数组内容
    close(DATA);
    

    getc 函数

    getc 函数从指定的 FILEHANDLE 返回单一的字符,如果没指定返回 STDIN。如果发生错误,或在文件句柄在文件末尾,则返回 undef。

    read 函数

    read 函数用于从缓冲区的文件句柄读取信息。这个函数用于从文件读取二进制数据

    read FILEHANDLE, SCALAR, LENGTH, OFFSET
    read FILEHANDLE, SCALAR, LENGTH
    

    如果读取成功返回读取的字节数,如果在文件结尾返回 0,如果发生错误返回 undef。

    对于所有从文件句柄中读取信息的函数,在后端主要的写入函数为 print:

    print FILEHANDLE LIST
    print LIST
    print
    
     # 只读方式打开文件
    open(DATA1, "<file1.txt");
    # 打开新文件并写入
    open(DATA2, ">file2.txt");
    # 拷贝数据
    while(<DATA1>)
       print DATA2 $_;
    close( DATA1 );
    close( DATA2 );
    

    文件重命名

    rename ("/usr/runoob/test/file1.txt", "/usr/runoob/test/file2.txt" ); #file1命名为file2
    
    unlink ("/usr/runoob/test/file1.txt");
    

    指定文件读写指针位置

    你可以使用 tell 函数来获取文件的位置,并通过使用 seek 函数来指定文件内的的位置:

    tell 函数用于获取文件读写指针位置:

    tell FILEHANDLE
    

    seek()函数是通过文件句柄来移动文件读写指针的方式来读取或写入文件的,以字节为单位进行读取和写入:

    seek FILEHANDLE, POSITION, WHENCE

  • FILEHANDLE:文件句柄,用于存放一个文件唯一标识符。
  • POSITION:表示文件句柄(读写位置指针)要移动的字节数。
  • WHENCE:表示文件句柄(读写位置指针)开始移动时的起始位置,可以取的值为0、1、2;分别表示文件开头、当前位置和文件尾。
  • open(DATA,"<a.txt") or die "出错!";
    #seek DATA,5,0;
    $position = tell DATA;
    print "$position\n";
    while(<DATA>)
        print "$_";
    close (DATA);
    dadad

    0表示指针位置。

    如果用seek进行指针偏移:

    open(DATA,"<a.txt") or die "出错!";
    $ss = seek DATA,5,0;
    print "$ss\n";
    $position = tell DATA;
    print "$position\n";
    while(<DATA>)
        print "$_";
    close (DATA);
    

    ​ 5

    返回1表示seek成功,后面没输出文件内容因为文件里五个字符后没内容了。

    测试文件是否存在,是否可读写等

    常用的是-e,文件或目录是否存在;-d ,是否位目录。

    my $file = "a.txt";
    my (@description, $size);
    if (-e $file)
        push @description, '是一个二进制文件' if (-B _);
        push @description, '是一个socket(套接字)' if (-S _);
        push @description, '是一个文本文件' if (-T _);
        push @description, '是一个特殊块文件' if (-b _);
        push @description, '是一个特殊字符文件' if (-c _);
        push @description, '是一个目录' if (-d _);
        push @description, '文件存在' if (-x _);
        push @description, (($size = -s _)) ? "$size 字节" : '空';
        print "$file 信息:", join(', ',@description),"\n";
    

    输出:a.txt 信息:是一个文本文件, 6 字节

    文件测试操作符如下表所示:

    opendir DIRHANDLE, EXPR  # 打开目录
    readdir DIRHANDLE        # 读取目录
    rewinddir DIRHANDLE      # 定位指针到开头
    telldir DIRHANDLE        # 返回目录的当前位置
    seekdir DIRHANDLE, POS   # 定位指定到目录的 POS 位置
    closedir DIRHANDLE       # 关闭目录
    

    显示所有的文件

    使用glob函数

    # 显示 /tmp 目录下的所有文件
    $dir = "/tmp/*";
    my @files = glob( $dir );
    foreach (@files ){
       print $_ . "\n";
    # 显示 /tmp 目录下所有以 .c 结尾的文件
    $dir = "/tmp/*.c";
    @files = glob( $dir );
    foreach (@files ){
       print $_ . "\n";
    # 显示所有隐藏文件
    $dir = "/tmp/.*";
    @files = glob( $dir );
    foreach (@files ){
       print $_ . "\n";
    # 显示 /tmp 和 /home 目录下的所有文件
    $dir = "/tmp/* /home/*";
    @files = glob( $dir );
    foreach (@files ){
       print $_ . "\n";
    
    opendir (DIR, '.') or die "无法打开目录, $!";
    while ($file = readdir DIR) {
      print "$file\n";
    closedir DIR;
    # 如果你要显示 /tmp 目录下所有以 .c 结尾的文件,可以使用以下代码:
    opendir(DIR, '.') or die "无法打开目录, $!";
    foreach (sort grep(/^.*\.c$/,readdir(DIR))){
       print "$_\n";
    closedir DIR;
    

    创建一个新目录

    $dir = "/tmp/perl";
    # 在 /tmp 目录下创建 perl 目录
    mkdir( $dir ) or die "无法创建 $dir 目录, $!";
    print "目录创建成功\n";
    
    $dir = "/tmp/perl";
    # 删除 /tmp 目录下的 perl 目录
    rmdir( $dir ) or die "无法删除 $dir 目录, $!";
    print "目录删除成功\n";
    
    $dir = "/home";
    # 将当期目录移动到 /home 目录下
    chdir( $dir ) or die "无法切换目录到 $dir , $!";
    print "你现在所在的目录为 $dir\n";
    

    13. 错误处理

    14. 特殊变量

    Perl 语言中定义了一些特殊的变量,通常以 $, @, 或 % 作为前缀,例如:$_。

    很多特殊的变量有一个很长的英文名,操作系统变量 $! 可以写为 ​$OS_ERROR。

    如果你想使用英文名的特殊变量需要在程序头部添加 use English;。这样就可以使用具有描述性的英文特殊变量。

    最常用的特殊变量为 $_,该变量包含了默认输入和模式匹配内容。

    foreach ('Google','Runoob','Taobao') {
        print $_;
        print "\n";
    
    foreach ('Google','Runoob','Taobao') {
        print;
        print "\n";
    

    上面两个的输出结果都是一样的。因为print 没有指定输出变量时默认用$_

    以下是几处即使没有写明 Perl 也会假定使用 $_ 的地方:

  • 各种单目函数,包括像 ord() 和 int() 这样的函数以及除 "-t"以外所有的文件 测试操作 ("-f","-d"),"-t" 默认操作 STDIN。
  • 各种列表函数,例如 print() 和 unlink()。
  • 没有使用 "=~" 运算符时的模式匹配操作 "m//"、"s///" 和"tr///"。
  • 在没有给出其他变量时是 "foreach" 循环的默认迭代变量。
  • grep() 和 map() 函数的隐含迭代变量。
  • 当 "while" 仅有唯一条件,且该条件是对 ""操作的结果进行测试时,$_ 就是存放输入记录的默认位置。除了"while" 测试条件之外不会发生这种情况。(助记:下划线在特定操作中是可以省略的。)
  • 特殊变量列举表

    https://www.runoob.com/perl/perl-special-variables.html

    15. 正则表达式

    Perl语言的正则表达式功能非常强大,基本上是常用语言中最强大的,很多语言设计正则式支持的时候都参考Perl的正则表达式。

    Perl的正则表达式的三种形式,分别是匹配,替换和转化:

  • 匹配:m//(还可以简写为//,略去m)
  • 替换:s///
  • 转化:tr///
  • 这三种形式一般都和 =~!~ 搭配使用, =~ 表示相匹配,!~ 表示不匹配。

    匹配操作符

    匹配操作符 m// 用于匹配一个字符串语句或者一个正则表达式,例如,要匹配 标量 $bar 中的 "run",代码如下所示:

    $bar = "I am runoob site. welcome to runoob site.";
    if ($bar =~ /run/){
       print "第一次匹配\n";
    }else{
       print "第一次不匹配\n";
    $bar = "run";
    if ($bar =~ /run/){
       print "第二次匹配\n";
    }else{
       print "第二次不匹配\n";
    
    第一次匹配
    第二次匹配
    
    模式匹配修饰符

    以下实例将变量 $string 中的所有小写字母转化为大写字母:

    $string = 'welcome to runoob site.';
    $string =~ tr/a-z/A-z/;
    print "$string\n";
    

    以下实例使用 /s 将变量 $string 重复的字符删除:

    $string = 'runoob';
    $string =~ tr/a-z/a-z/s;
    print "$string\n";
    
    $string =~ tr/\d/ /c;     # 把所有非数字字符替换为空格
    $string =~ tr/\t //d;     # 删除tab和空格
    $string =~ tr/0-9/ /cs    # 把数字间的其它字符替换为一个空格。
    

    更多正则表达式规则

    匹配含有 abc 的字符串 (pattern) () 这个符号会记住所找寻到的字符串,是一个很实用的语法.第一个 () 内所找到的字符串变成 $1 这个变量或是 \1 变量,第二个 () 内所找到的字符串变成 $2 这个变量或是 \2 变量,以此类推下去. /pattern/i i 这个参数表示忽略英文大小写,也就是在匹配字符串的时候,不考虑英文的大小写问题. \ 如果要在 pattern 模式中找寻一个特殊字符,如 "*",则要在这个字符前加上 \ 符号,这样才会让特殊字符失效