perl语言入门第六版读书笔记

本文最后更新于:2025年11月19日 下午

perl语言入门第六版

简介

  • 本书涵盖的最低版本5.8
  • CPAN,perl综合典藏网,里面包含扩展,文档等
  • perl解析器能一次完成编译和运行这两个动作。(注意是有先编译,即运行前就可以检查到整个代码的语法错误)

标量数据

  • perl每个语句必须以分号;结束
  • perl的数字可以通过下划线分割,方便理解0x1234_2222_ffff
  • perl虽然都是浮点数,但是支持取模运算(%)
  • 如果源代码中有ascii之外的字符,那么加上一行use utf8;,让编译器正确解释你的代码。
  • 单引号内除了反斜杠和自身,所有字符都代表它们自己,包块换行符
  • 字符串的连接操作使用的.
  • 字符串的重复操作使用的小写字母x"aaa" x 3重复aaa 3次。
  • perl里面包含大量的默认行为,当发现程序不对时,可以打开警告use warnings;,也可在命令行中添加-w选项。use warnings;说的更灵活,可以指定某几行代码警告。
  • 标量的变量前缀为$
  • 字符串比较运算符使用的eq,ne不等,lt小于操作符
  • 字符串’0’非空,但是代表条件假。它是唯一的非空字符串假
  • <STDIN>获取用户输入
  • chomp($text)去掉结尾的换行符,chomp($text=<STDIN>)
  • 要判断某个字符串是undef而不是空字符串,可使用defined函数,如果是undef,那么返回假
  • print函数中内插变量时,如果变量后面紧跟字符,那么变量应使用形式print "${var}a"形式,避免perl认为变量名包含后面紧跟的字符a

字符串

  • 截取字符串函数substr
    my $part = substr($string, $pos, $length);
    1
    2
    # 截取开头4个字符,末尾两个字符,用..拼接起来。
    print substr($_, 0, 4) . ".." . substr($_, -2, 2);

列表和数组

  • 引用整个数组时,数组名前面添加@符号。
  • 数组下标从0开始,最后一个索引值为$#array,取最后一个元素,可直接用$array[-1]
  • 可用两个点..操作符产生一个整数列表,如1..100,只能递增。
  • 可用qw操作符,产生一个字符串列表,perl发明人可真懒
  • pop读出数组最后一个元素并返回,push添加元素到最后
  • shift,unshift操作最左边的元素,和pop,push类似
  • @removed = splice @array,idx,del_num,@insert_array, 移除idx开始的n个元素,并插入一个数组,返回移除的数组。后两个参数可选,默认移除从idx到最后的所有元素。
  • print @array会将数组元素一个个打印出来,print "@array",会在数组元素中间加一个空格打印出来。
    1
    2
    3
    foreach $i (qw / aa bb cc /){
    print "$i"
    }
  • foreach的控制变量并没有复制数组里面的值,相当于引用。修改控制变量会直接修改到数组本身。
  • foreach可以省略控制变量,会使用默认变量$_
  • reverse返回一个持续相反的列表,并不改变原列表
  • sort返回ascii序的列表,也不会改变原列表
  • 数组的名称在列表上下文,返回元素的列表。在标量的上下文,返回数组元素个数。
  • chomp(@lines = <STDIN>) 读所有行,并移除换行符

子程序

  • 不需要子程序事先声明,如果有两个同名子程序,后面的会覆盖前面的
  • 所有子程序都有返回值,没有明确指定return的话,返回值就是最后一次运算结果的值
  • perl自动将参数列表存在名为@_的数组变量中,那么第一个参数为$_[0]
  • 默认perl的所有变量都是全局变量,创建私有变量要使用my
  • my操作符后面不加括号,只能声明单个局部变量,加括号才能声明多个,实际上是声明的一个列表。
  • use strict让perl严格约束代码
  • 如果编译器在调用子程序时看到过子程序的定义,那么调用子程序的时候可以省略&号,添加&也可以避免和perl内置函数同名的问题,&总是会调用自定义的子程序。
  • 单写一个return不给任何参数,表明返回的空。对于标量上下文,就是undef,列表上下文就是空列表。
  • 持久私有变量。类似于静态变量。state操作符声明,需要使用use feature 'state'语句

输入输出

1
2
3
4
5
6
7
while(<>){
chomp;
print "get line: $_\n";
}

print <>; #相当于cat命令
print sort <>; #相当于sort命令
  • 建议用大写字母命名文件句柄
  • 有6个特殊的文件句柄是perl保留的:STDIN,STDOUT,STDERR,DATA,ARGV,ARGVOUT
  • 可通过如下命令打开文件句柄
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
open FH, 'filename'; //默认读打开
open FH, '<filename';//
open FH, '>filename';//
open FH, '>>filename';//追加

# 也可以用三个参数的写法
open FH, '>','filename';
# 可以指定编码
open FH, '<:encoding(UTF-8)', 'filaname';

#关闭
close FH;

# 从5.6开始,句柄可以存放到变量中,方便作为参数传递,控制作用域
my $fh;
open $fh, ">", "filename";
  • 二进制方式读写binmode
  • die "some error: $!";结束程序并打印东西,$!表示系统错误信息,类似strerror。
  • die会自动打印行号和文件名,如果不需要打印这个,那么只需在后面加一个换行符。
  • warn函数差不多,只是不会终止程序运行。
  • 5.10开始,可以用use autodie;。它如果检查到系统调用级别的错误,就会自动die。相当于不用检查文件打开是否成功这类错误了。
  • $0中保存了程序的名字
  • 文件句柄的使用和之前用得STDIN差不多。print LOG "xxxx",将字符串输出到LOG这个句柄里。
  • 重新打开已经打开的句柄时,perl会自动关闭原来的句柄,比如可通过如下语句重定向错误输出到文件
    1
    open STDERR, ">>error.log";
  • 5.10开始有一个say函数,和print差不多,只是自动加一个换行符。

ARGV相关

  • $ARGV 表示参数命令行的文件中,当前正在处理的文件名

  • @ARGV 里面保存了命令行的参数列表,一般就是输入的文件名,在<>操作中,列表的元素会一个个移除

  • ARGV表示<>当前正在处理的文件句柄。

哈希

  • 键必须是唯一的字符串

  • 访问hash的语法为$hash{$key},大括号

  • 访问整个哈希,可以使用%作为前缀。哈希可以转换为列表。列表也可以赋值给hash。

  • %reverse_hash = reverse %any_hash 可以建立一个反序的哈希,即key-value变为value-key。

  • 给hash赋值可以使用列表的形式:%some_hash = ('key1', 22, 'key2', "333")。这种形式不方便看。可以使用胖箭头 => ,对perl而言,它只是逗号的另一种写法,唯一的区别在于胖箭头左边的裸字都会加上引号。于是可以这样初始化hash:

    1
    2
    3
    4
    5
    6
    7
    8
    my %some_hash = (
    key1 => "1231",
    key2 =>123,
    key3 => { # hash嵌套
    aaa => 222,
    bbb=> 233,
    }
    );
  • 注意hash初始化使用的圆括号,嵌套时用大括号

  • 访问hash元素的时候可以省略key的引号,$hash{"aaa"}$hash{aaa}同义。

  • my @k = keys %hashmy @v = values %hash 两个函数可用于提取所有key和value

  • each函数变量hash

    1
    2
    3
    while (($key, $value) = each %hash){
    ;
    }

    echo会从hash中返回键值对,这是一个两个元素的列表。而赋值后得到的列表在标量上下文就是元素个数,为2。所以一直循环,知道取不出来值。

  • exists函数用户检查hash中是否存在某个键:if(exists $books{leon})

  • delete $books{leon} 函数用于删除某个键值对。

  • hash元素可以内插,但是不支持内插整个hash。如果想要打印整个hash,可以先把hash赋值给列表,然后内插整个列表。

  • %ENV这个内置的hash存储了环境变量

漫游正则表达式王国

  • 正则表达式和glob(shell的文件名匹配模式)不是同一个东西
  • 捕获分组时,反向应用的方法是\1,\2。如何知道是第一个还是第二个,从左到右数括号的序号即可。从perl 5.10开始支持\g{N}来表示是第几组,可以更方便,可以指定负数
  • perl 5.10开始引入\R能匹配任意一种换行符
  • 反义简写,\D非数字,\W非单词, \S非空白符

用正则表达式进行匹配

  • m/xxx/flag ,如果以//作为定界符,那么m可以省略。当然为了方便可以用其他的定界符。flag有:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    i -- 忽略大小写
    m -- 多行匹配
    s -- 匹配任意字符,默认情况下点号 . 无法匹配换行符,如果指定了这个就可以匹配了。
    x -- 忽略正则表达式中的空白符,这样方便分割正则表达式,让正则表达式看起来更清晰(可以分行写,每行写注释)
    p -- ^PREMATCH, ^MATCH, ^POSTMATCH变量使用

    perl 5.14开始可以指定如果解释字符:
    a -- ascii
    u -- unicode
    l -- 使用本地化的语言设置
  • 锚位,不匹配任何字符,但可以指定位置

    1
    2
    3
    4
    5
    6
    ^ -- 行首
    $ -- 行尾
    \A -- 字符串的绝对开头,多行的情况下和^有一点区别,单行和^同义
    \Z -- 字符串的绝对末尾
    \b -- 单词边界
    \B -- 非单词边界
  • 绑定操作符=~,默认情况下,正则匹配$_变量,$var =~ /reg/可以使其匹配$var变量。

  • 正则表达式中可以内插变量。

  • 如果正则表达式有括号,表示要捕获这个分组,但有时不想捕获,可以使用(?:xxx),表示不捕获这个分组。

  • 命名捕获。perl 5.10开始,可以直接把捕获的分组存入内置的%+这个hash变量中, (?<name>regex)。使用这个变量的方法为$+{name}

  • 使用命名捕获后,反向引用的语法也随之改变为\g{label}

  • 自动捕获变量。perl会自动把匹配前,匹配,匹配后的三串字符串存入如下三个变量,perl 5.10后,使用/p flags会将结果存入更容易记忆的几个变量。

    1
    2
    3
    4
    $`  --- ${^PREMATCH}
    $& --- ${^MATCH}
    $' --- ${^POSTMATCH}
    # 后面的三个变量也好理解,外面的花括号围住表示其中是完整的变量名,变量名前面加^避免重复。

用正则表达式处理文本

  • s///进行替换,返回bool值,成功为真,否则为假

  • /g全局替换

  • m//一样,替换也可以使用不同的定界符,对于没有左右之分的字符,写三个就行,如果不是就需要成对写,如下几种意思一样:

    1
    2
    3
    4
    s/123/456/
    s|123|456|
    s{123}{456}
    s[123](456)
  • m//一样,替换也可以使用绑定操作符$aa =~ s/123/456/

  • /r不直接操作源字符串,而是返回一个新的。my $copy = $orig =~ s/111/222/

  • 大小写转换

    1
    2
    3
    4
    \U -- 把之后的所有字符转为大写, s/aaa/\U$var/
    \L -- 把后面的所有字符转为小写
    \E -- 停止后面的字符转换
    \u, \l -- 只转换一个字符

    上面的转换在print里面也是可以用得。

  • split /separator/, '$string'操作符。分割字符串,返回列表。默认以空白字符分割,默认操作$_变量。

  • 如果要在split的模式中使用分组,那么要使用分组不捕获写法(?:)

  • join aaa, @array,在字符串中加入粘合剂

  • 在列表上下文,使用m//,匹配成功返回所有捕获分组的列表,失败返回空列表

  • $^I = ".bak"变量,设置后,钻石操作符s///时,会直接写原文件,但会有一个备份文件生成。如果设置这个字符串为空串,那么不会生成备份文件。

    1
    2
    3
    4
    5
    $^I = ".bak";
    while (<>){
    s/aaa/bbb/g;
    print;
    }
  • 有时替换可以先使用占位符\0,或者chomp后使用\n

其他控制结构

  • 表达式修饰符,即可以在一行里面写上if , foreach这种。使用foreach修饰符的时候无法自选控制变量,必须使用$_

    print "ok" if $ok;

  • foreach和for其实等价,如果括号内没有分号,那么是foreach循环,如果有分号那么是for循环。

  • last操作符等价于break

  • next操作符等价于continue

  • redo操作符合next相似,区别在于,next会继续下一次迭代,而redo会重新执行这次迭代

  • 带标签的块,可以让里层直接跳到外层的某个循环点

  • 定义或操作符//,看着跟着注释符一样…。如果左侧的值未定义(undef),那么使用右侧的值,常用于赋默认值

    my $last_name = $last_name{$someone} // '(no last name)';

perl模块

1
2
3
4
use File::Basename; # 导入模块
use File::Basename qw/basename/; # 导入模块的特定函数
basename $name; #只是使用模块内函数名
File::Basename::dirname $name; # 全称使用模块函数
  • 还有中面向对象的模块,使用的使用需要使用瘦箭头->

DateTime模块

文档

1
2
3
4
5
6
7
8
9
10
11
12
use DateTime; 
my $dt = DateTime->now;
$ymd = $dt->ymd; # 2002-12-06
$ymd = $dt->ymd('/'); # 2002/12/06 - also date

$mdy = $dt->mdy; # 12-06-2002
$mdy = $dt->mdy('/'); # 12/06/2002

$dmy = $dt->dmy; # 06-12-2002
$dmy = $dt->dmy('/'); # 06/12/2002

$hms = $dt->hms; # 14:02:29

Time::Piece模块

(5.10内置)

文档

1
2
3
4
5
6
7
8
use Time::Piece;

my $t = localtime; # 得到一个当前时间的对象,里面可以便捷的访问时间
$t->sec # also available as $t->second
$t->min # also available as $t->minute
$t->hour # 24 hour
$t->hms # 12:34:56
$t->hms(".") # 12.34.56

安装模块

先在cpan网搜索自己需要什么模块,然后通过命令安装,
示例如下,第一次可能需要配置,自动即可

1
2
3
$ sudo cpan
cpan[1]> install JSON
cpan[2]> install Text::CSV

文件测试

1
2
3
if(-e $filename){
print "xxxxxx\n";
}

image-20220227095918759

image-20220227095959828


perl语言入门第六版读书笔记
https://leon0625.github.io/2022/02/20/d716b92474cf/
作者
leon.liu
发布于
2022年2月20日
许可协议