前言
- 在看这篇文章之前,推荐先看下《卧槽!perl和C语言实现对比,perl代码量太赞了!》,不知道你看了吗2?
- 推荐一些文章:
- Perl系列文章
- 两个半小时学会Perl
- Perl 教程
- 本文内容是基于《Perl语言入门·第七版》整理所得,而且章节标题和书籍基本对应。
- 本文食用方式,推荐使用搜索关键字和查看目录的方式快速索引到需要的内容;
- 本文内容全部是手敲的,难免有错误,望各位看客多多包涵!
- 本文涉及到的习题,基本都实现了,并且同步在了Gitee,按需下载
第1章 简介
- 《Perl语言入门·第七版》
- https://www.learning-perl.com/可以下载源代码
- https://www.cpan.org/是Perl综合典藏网,包含很多基于Perl的内容,如源代码、安装程序、示例文件
第2章 标量数据
- scalar(标量)
- 标量数据:表示数据的内容,就是值;
- 标量变量:表示存储标量数据的容器;
数字
前置零的写法只用于表示数字直接量,不能用于字符串和数字间的自动转换。
字符串
养成加上use utf8;
的习惯。
单引号内的字符直接量
- 单引号字符串中,反斜线表示转义的两种情况:
反斜线后面跟反斜线或单引号
;
双引号内的字符直接量
- 与单引号相比,转义字符的内容更加强大。
组合 | 意义 |
---|---|
\n | 换行 |
\t | 水平制表符 |
\r | 回车 |
\f | 换页符 |
\b | 退格 |
\a | 系统响铃 |
\e | 跳出(ASCII编码的转义字符) |
\\ | 反斜线 |
\“ | 双引号 |
\l | 将下个字母转为小写 |
\L | 将它后面的所有字符都转为小写,直到\E 为止 |
\u | 将下个字母转为大写 |
\U | 将它后面的所有字符都转为大写,直到\E 为止 |
\E | 结束\L、\U和\Q开始的作用范围 |
字符串操作符
操作符可以使用句点符号.
进行拼接!
Perl的内置警告信息
- 形式1:
#!/usr/bin/perl
use warnings;
- 形式2:
#!/usr/bin/perl -w
- 形式3:
运行时加上-w
选项! use diagnostics;
报告核心内容
标量变量(variable)
和其他语言一样,只是perl的变量需要拿钱买来,形如$fred
print输出结果
- 用
say
代替print
输出结果
perl -E 'say q(hello, world)' [255]
hello, world
字符串中的标量变量内插
变量内插
有时候又叫双引号内插
!
比较操作符
- 注记:
lt
:less than
gt
:greater
eq
:equal
比较 | 数字 | 字符串 |
---|---|---|
相等 | == | eq |
不等 | != | ne |
大于 | >= | lt |
小于 | < | gt |
小于或等于 | <= | le |
大于或等于 | >= | ge |
if控制结构
- 和其他语言一样
获取用户输入
$line = <STDIN>
chomp操作符
- 取消末尾的换行符
chomp函数
的返回值是移除的字符数
chomp($text = <STDIN>);#读取不带换行符的输入
#等价于
$text = <STDIN>;
chomp($text);
while控制结构
- 与其他语言一样
undef值
ubdef
作为数字、字符串使用时会被视作数字零
、空字符串
defined函数
defined函数
:判断某个字符串是否为空,如果是undef,返回假!
习题
第3章 列表与数组
访问数组中的元素
注意$fred[0]
与fred
是两个不同的东西
特殊的数组索引
如果数组定义如下:
$name[0] = 'a';
······
$name[88] = 'asd';
最后一个元素的索引可以是$#name
和-1
列表直接量
(1, 2, 3) #包含三个数字的列表
(1,"fred", 2) #列表内元素存储格式灵活
(1..100) #从1到100的整数序列
qw简写
qw
表示为quoted word
用引号引用的词或quoted by whitespace
用空白引用的词;
("fred", "barney", "betty", "wilma", "dino")
# 等价的几种写法,少了很多引号,方便使用!
qw( fred barney betty wilma dino )
qw! fred barney betty wilma dino !
qw{ fred barney betty wilma dino }
qw[ fred barney betty wilma dino ]
qw/ fred barney betty wilma dino /
qw< fred barney betty wilma dino >
qw# fred barney betty wilma dino #
······
列表的赋值
pop和push操作符
删除
和增加
数组末尾元素
shift和unshift操作符
删除
和增加
数组开头元素
splice操作符
splice 最多接收4个参数,分别为目标数组
,操作数组的开始索引
,操作的元素个数
,替换的元素
字符串中的数组内插
- 注意在使用@符号的时候,在输入邮箱的时候,需要用转义符!
foreach控制结构
- 和c++中的增强for循环类似。在这里,perl会有默认变量来接收!
Perl最喜欢用的默认变量:$_
reverse操作符
- 操作后如果需要更数组内容,就需要用数组去接收,否则不会生效!
sort操作符
- 此处的sort还不能很完美的支持数字的排序,因为仅仅根据ascii顺序排序的!
标量上下文与列表上下文
- 此处想表达的是,相同的符号在不同的语境下有不同的含义!
- 比如,
数字 + 数组
得到的是数字
,数组名与数字进行比较时,数组名返回的是数组的长度
在标量上下文中使用产生列表的表达式
- 同样是
reverse数组
操作,接收的类型不同,得到的内容就不同! - 如果是
数组接收
,以数组元素
为最小单位翻转 - 如果是
标量接收
,以最小字符
为最小单位翻转
在列表上下文中使用产生标量的表达式
列表上下文中的
- 如果接收的是数组类型,则可以多行输入;
习题
第4章 子程序
- 前文用到内置的系统函数有
chomp
,reverse
,print
- 和其他语言类似,perl也可以自己定义子程序,子程序名属于独立的命名空间,
调用子程序
一般需要加上&
定义子程序
- 子程序的形式,如下所示:
sub marine {
$n += 1; # 全局变量$n
print "Hello, sailor number $n!\n"
}
- 与c语言相比,perl子程序的定义可以出现在任何位置,也不需要出现函数的声明;
- 如上的子程序,操作的是全局变量,也就是说,前文用到的
都是全局变量
;
调用子程序
- 调用子程序,又可以叫
呼叫子程序
; - 子程序名前面加上
&
就可以调用,如调用上面的子程序可以用&marine;
- 如果学过c/c++,不知道这里是否可以理解为取内存中的地址,然后执行?
返回值
- 调用子程序都会有返回值
- 每次写返回值表达式显得费时费力
- perl的
返回值
简化为,返回子程序执行过程中最后一次运算的结果
- 小心检查最后的返回值是不是你想要的内容!你晓得吧!
参数
- 在调用的传参时候,perl会自动参数劣列表转化为数组变量
@_
; - 如下定义的子程序,可以使用
&max(10,15);
这样的形式进行传参调用!
sub max {
if(@_[0] > @_[1]){
$_[0];
} else {
$_[1];
}
}
子程序中的私有变量
- 使用
my
定义私有变量,如下所示
sub max {
my($m, &n); # 该语句块中的新私有变量
($m, &n) = @_; # 将该参数赋值给变量
if ($m > $n) { $m } else { $n } # 只有写成一行时,内部的分号才可以省略
}
- 当然定义和初始化可以放在一行语句内,如下:
sub max {
my($m, &n) = @_; # 对子程序的参数命名
if ($m > $n) { $m } else { $n } # 只有写成一行时,内部的分号才可以省略
}
变长参数列表
- 可以在子程序内部开头判断传入参数的个数,是否符合预期!
sub max {
if (@_ != 2) {print "WARNING!应该传入两个参数!"}
my($m, &n) = @_; # 对子程序的参数命名
if ($m > $n) { $m } else { $n } # 只有写成一行时,内部的分号才可以省略
}
改进版的&max子程序
- 这里其实就是
选择比较法
,需要理解的就是@_
和$_
; @_
:子程序参数列表$_
:foreach循环读到的值
#!/usr/bin/perl -w
sub max{
my($max_so_far) = shift @_;
foreach (@_) {
if ($_ > $max_so_far) {
$max_so_far = $_;
}
}
$max_so_far;
}
$maximum = &max(3, 5, 10, 4, 6);
print $maximum;
空列表参数
- 需要注意的是,返回值可能为undef
用my声明的词法变量
- my操作符并不会更改变量赋值时的上下文!
my($num) = @_; # 列表上下文,和($num) = @_;相同
my $num = @_; # 标量上下文,和 $num = @_;相同
- my操作符不加括号时,只能声明靠近的单个词法变量!
- 推荐使用my操作符定义自己的私有变量
use strict 编译指令
- 开启这个编译指令,就要求在自定义变量声明前,必须加上
my
use strict;
:强制使用严格、良好的编程风格use v5.12
:自动加载strict编译指令- 大部分人的建议:比屏幕长的程序都应该加上
use strict;
return操作符
- 满足条件后,终止子程序!
省略与号
- 在调用子程序时,传入参数时,可以完全省略
&
:编译器能明显感知到调用的是子程序 - 自定义子程序,如果命名与内置函数重名,调用时一定要加上
&
非标量返回值
- 返回值可以是标量,也可以是列表!
持久化私有变量
- 此处引入关键字
state
,在子程序中,可以一直存在,小编认为是c语言形式
的static的修饰,仍然在全局区!
子程序签名
- 乍一看,这个特性的加入,使其
表现形式越来越像c语言函数的写法
!
习题
第5章 输入与输出
读取标准输入
- 行输入操作符:
<STDIN>
与Perl的默认变量$_
之间并无直接关联! comp
:截掉最后的换行符defined
:可以用来判断是否读取到末尾!- 下面有两个程序,执行效果相同,但他们的原理真的相同吗?
- while实现的:
while(<STDIN>) {
print "I saw $_";
}
- foreach实现的:
foreach(<STDIN>) {
print "I saw $_";
}
- 结果就是,不一样:
foreach是先把数据全部读进来
;而while是读一行执行一行
;如果要处理400MB数据,估计还是选择while好一点!
来自钻石操作符的输入
- 钻石操作符
<>
的名字竟然是Larry的女儿命名的! - 钻石操作符是行输入操作符的特例,通常会处理所有的输入,所以在程序中一般只出现一次!
- 下面展示两个相同功能的代码!
- 代码1:
while(<>){
chomp;
print "It was $_ that I saw!\n";
}
- 代码2:
while(defined($line = <>)){
chomp($line);
print "It was $_ that I saw!\n";
}
双钻石操作符
- 如果命令行传入的文件名中包含==管道符
|
==等特殊字符,就会引发管道等特殊操作。 - 因此引入
<<>>
双钻石操作符,功能没变
调用参数
钻石操作符
并不会检查命令行参数,其实也只是把命令行参数存放到@ARGV
中- 因此,可以通过修改
@ARGV
的内容,强制修改钻石操作符要读取的内容 - 如
@ARGV = qw{larry moe curly}; #强制让钻石操作符只读取这三个文件
while(<>){
chomp;
print "It was $_ that I saw in some stooge-link file!\n"
}
输出到标准输出
- 下面两种打印输出有什么区别?
print @array;
print “@array”;
- 第二行输出的时候,会在元素之间添加空格;
- 行缓冲,也是是用换行符来进行刷新的!
print
加括号和不加括号的区别,注意!
用printf格式化输出
- 这里和c语言的格式高度类似,
printf
使用后面的括号是选择性的,如果加上,和C语言就一样了! 参数宽度
也可以作为参数
另外指定!- 如下的格式:
#!/usr/bin/perl -w
use strict;
use warnings;
print "Hello world\n";
printf("这里直接是以字符串的格式输出的:\n");
printf "%*s\n", 10, "wilma";
printf("%*s\n", 10, "wilma");
printf("注意,此处参数宽度用参数传入:\n");
printf "%*.*f\n", 6, 2, 3.1415926;
printf("%*.*f\n", 6, 3, 3.1415926);
- 运行结果如下:
Hello world
这里直接是以字符串的格式输出的:
wilma
wilma
注意,此处参数宽度用参数传入:
3.14
3.142
数组和printf
- 有没有发现和python的格式化输出也一样!
- 再一次感受到,编程思想比编程语言本身重要很多!
my @items = qw{ wilma dino pebbles };
printf "printf输出添加括号:\n";
printf("The items are:\n".("%10s\n" x @items), @items);
printf "printf输出不加括号:\n";
printf "The items are:\n".("%10s\n" x @items), @items;
- 运行结果:
printf输出添加括号:
The items are:
wilma
dino
pebbles
printf输出不加括号:
The items are:
wilma
dino
pebbles
文件句柄
- 注意联系
I/O
操作,6个保留的文件句柄:STDIN
、STDOUT
、STDERR
、DATA
、ARGV
、ARGVOUT
打开文件句柄
open CONFIG, 'dino'; # 可读可写
open CONFIG, '<dino'; # 只读
open BEDROCK, '>fred';# 可写
open LOG, '>>logfile';# 可追加写
open CONFIG, 'dino'; # 可读可写
open CONFIG, '<', 'dino'; # 只读
open BEDROCK, '>', 'fred';# 可写
open LOG, '>>:encoding(UTF-8)', 'logfile';# 可追加写,还可以指定特定编码
以二进制方式读写文件句柄
- 句柄前加上
binmode
,直接以二进制数据流的方式读写。即使在二进制文件中碰巧出现内部编码和换行符相同的字符,也不会将其当做文本文件中的换行符来处理。
异常文件句柄的处理
my $success = open LOG, '>>','logfile'; # 通过返回值可以判断是否成功?
if(!$success){
# open 操作失败
}
关闭文件句柄
- 有打开就要有关闭,
close
,就如C中,有malloc就要有free;C++中,有new就要有delete;
用die处理致命错误
die
函数的参数是要发出的错误信息文本,一般会输出到标准错误流,同时让程序退出运行!- 注意下面程序,
$!
记录的是程序最后返回给操作系统的错误代码! - 小编怀疑,
die
也是由linux中系统函数perror
封装的,但只是猜测
if(! open LOG, '>>', 'logfile') {
die "Cannot create logfile:$!";
}
用warn发出警告信息
- 与
die
相比,warn
不会终止程序的运行!
自动检测致命错误
- 在使用的时候,在前面加上
use autodie;
这种声明,就会自动判断!
使用文件句柄
- 有点像c中的
sprintf
print LOG "Captain's log, stardate 3.145159\n" #输出到文件句柄 LOG
printf STDERR "%d percent complet.\n", $done/$total * 100;
改换用于输出的默认文件句柄
- print和printf的默认输出句柄是
STDOUT
,我们可以使用select BEDROCK;
格式来进行切换输出句柄
重新打开标准文件句柄
- 在重新打开了 STDERR之后,任何从Perl产生的错误信息都会送到新的文件里。但如果程序执行到die这部分的代码,那会怎样呢?也就是说,如果无法成功打开文件来接收错误信息,那么错误信息会流到哪里去?
- 在重新打开这三个系统文件句柄 STDIN、 STDOUT或 STDERR失败时,Perl会热心地帮你找回原先的文件句柄。也就是说,Perl只有在成功打开新的句柄连接时,才会关闭默认的系统文件句柄。
用say来输出
- 输出内容并换行时,可以使用
say
函数 - 这是perl 5.10的新特性,可以多试试
标量变量中的文件句柄
- 使用裸字和标量变量,根据需要进行选取
习题
第6章 哈希
什么是哈希?
名字
之前有一个美元符号
,之后有一个花括号
- sv中的关联数组
访问哈希元素
$hash{$some_key}
访问整个哈希
- 用
%
作为前缀,%hash
胖剪头
=>
左边是键,右边是值;
哈希操作函数
keys和values
my %hash = ('a' => 1, 'b' => 2, 'c' => 3);
my @k = keys %hash;
my @v = values %hash;
my $count = keys %hash; # 返回键值对的个数
if(%hash) {
print "hash 不为空";
}
each函数
- 遍历哈希的每个键值对,可以使用
each
,每次调用都会返回一个键,一个值
while (($key, $value) = each %hash) {
print "$key => $value\n";
}
- 一个推荐的函数
foreach $key (sort keys %hash){
$values = $hash($key);
print "$key => $value\n";
# 或者,可以略去额外的 $value 变量
# print “$key => $hash{$key}\n”;
}
哈希的典型应用
exists函数
- 检查哈希中是否存在某个键
if (exists $hash{"key"}){
# 存在
}
delete函数
- 直接删除指定的键和值。如果没有这样的键,那就结束,也不会出现警告或错误提示;
哈希元素内插
foreach $person (sort keys %books) {
if ($books{$person}) {
print "$person has $books{$person} items";
}
}
特殊哈希%ENV
- Perl会把环境信息放到特殊哈希
%ENV
里面
习题
第7章 正则表达式
- regular expression
序列
$_ = "yabba dabba doo";
if (/abba/) {
print "It matched\n";
}
- 如上所示,两个斜线就是匹配操作符号!
动手实践不同模式
- 上面的小程序就够了
通配符
- 点号
.
能匹配除换行外的任意单个字符
量词
- 指定匹配项的的重复次数。
- 最简单的量词是
?
:前一个字符出现n次或0次 - 量词
*
:前一个字符出现n次或0次,常用于匹配不固定长度的空白字符 .*
:贪婪匹配,可以匹配任意非换行字符任意次
模式分组
- 用圆括号
( )
将模式字符串分组 (.)\1
:匹配连续出现的两个同样字符
择一匹配
|
:或的关系
字符集
[a=z] # a到z的全部小写字母
[-a] # 连字符 或者 a
[^n-z] #不是n到z的字符
简写的反义形式
[a]
的相反形式可以是[^a]
简写 | 匹配 |
---|---|
\d | 十进制数字 |
\D | 非十进制数字 |
\s | 空白字符 |
\S | 非空白字符 |
\h | 水平空白字符(Perl 5.10起支持) |
\H | 非水平空白字符(Perl 5.10起支持) |
\v | 纵向空白字符(Perl 5.10起支持) |
\V | 非纵向空白字符(Perl 5.10起支持) |
\R | 一般化的行结尾符号(Perl 5.10起支持) |
\w | 单词字符 |
\W | 非单词字符 |
\n | 换行符(不是真正的简写) |
\N | 非换行符(Perl 5.18 起属于稳定特性) |
Unicode字符属性
锚位
\A
:匹配字符串的绝对开头\z
:匹配字符串的绝对末尾\b
:单词锚位,匹配单词边界
习题
第8章 用正则表达式进行匹配
用m//进行匹配
- 模式匹配操作符:
m( )
,m< >
,m{ }
,m[]
,其中选择斜线作为定界符时,一般省略前面的m,变成了/ /
模式匹配修饰符
用/i
进行大小写无关的匹配
用/s
匹配任意字符
/.*/s
:可以匹配到换行符- 如果不习惯用
/s
修饰符,可以使用[\D\d]
,[\S\s]
等,原理就是数字字符
以及非数字字符
组合就是任意字符。
用/x
加入辅助空白字符
- 使用这个之后,可以在模式里使用空格或换行使得代码可读性更高!
联合使用修饰符
- 单词匹配多想修饰符
if (/barney.*fred/is){# 同时使用 /i 和 /s
# 匹配成功
}
- 用花括号作为定界符,用vim就可以自动定位跳转
if (m{
barney
.*
fred
}isx){ # 或同时使用 /i 、 /s 和 /x
# 匹配成功
}
选择字符的解释方式
- Perl 5.14 开始增加了一些用于告诉Perl如何解释字符意义的修饰符,主要是:对大小写的处理以及对字符集合的阐释。
行首和行尾锚位
^
与\A
一样,$
与\z
一样- 如果加上
/m
修饰符,/^/m
就会匹配字符串开头和换行符之后的内容(就是每行开头)
绑定操作符=~
- 正则表达式默认匹配的目标文本是
$_
,我们可以使用绑定操作操作符=~
指定要匹配的目标文本。
捕获变量
- 捕获变量,把匹配到的内容用标量存储起来,方便调用!一般使用圆括号
()
进行捕获
捕获变量的存续期
- 捕获变量的内容一般会保持到下次成功匹配为止,我们可以将其保存下来的;
禁用捕获的括号
- 在左括号后加上
?:
,此时的括号仅用于分组,不再捕获匹配字符串。
命名捕获
- 使用如下的捕获标签,可以随意移动位置,并加入更多的捕获括号!
use v5.10;
my $names = 'Fred or Barney';
if ($names =~ m/(?<name1>\w+) (?:and|or)(?<name2>\w+)){
say "I saw $+{name1} and $+(name2)";
}
自动捕获变量
- $`:匹配保存之前的内容
- $&:匹配保存 的内容
- $’:匹配保存之后的内容
- 修饰符
/p
可以对当前的表达式开启类似的自动捕获变量,变成了${^PREMATCH}
,${^MATCH}
,${^POSTMARTCH}
优先级
正则表达式优先级表
正则表达式特性 | 示例 |
---|---|
元括号(分组或捕获) | (···),(?:···),(? |
量词 | a*,a+,a?,a{n,m} |
锚位和字符序列 | abc, ^, $, \A, \b,\z,\Z |
择一 | a|b|c |
原子 | a,[abc],\d,\l,\g{2} |
模式测试程序
#!/usr/bin/perl
while (<>) { # take one input line at a time
chomp;
if (/YOUR_PATTERN_GOES_HERE/) {
print "Matched: |$`<$&>$'|\n"; # the special match vars
} else {
print "No match: |$_|\n";
}
}
习题
第9章 用正则表达式处理文本
用s///
进行替换操作
s/st1/st2; #试图将st1替换为st2
用/g
进行全局替换
s/\s+/ /g; # 将任意连续的空白转换成单一空格
s/\A\s+//g; # 将开头的空白字符替换成空字符串
s/\s+\z//g; # 将结尾的空白字符替换成空字符串
s/\A\s+|\s+\z//g; #去除开头和结尾的空白字符
不同的定界符
- 和
m//
和qw//
一样,可以改变s///
的定界符
替换操作的修饰符
- 除了
/g
修饰符外,我们还可以把用在普通模式匹配中的/i
、/x
和/s
修饰符用在替换操作中
绑定操作符
=~
为s///
指定不同的替换目标
非破坏性替换
- 如果需要同时保留原始字符串和替换后的字符串,该怎么办?
- 复制拷贝一份再替换
my $original = 'Fred ate 1 rib';
my $copy = $original;
$copy =~ s/\d+ ribs?/10 ribs/;
- 等价于
(my $copy = $original )=~ s/\d+ ribs?/10 ribs/;
- perl 5.14增加了一个
/r
字符串,就会保留原来字符串中的值不变,把替换结果作为替换操作的返回值返回
use v5.14;
my $copy = $original =~ s/\d+ ribs?/10 ribs/r;
大小写转换
\U
将它后面的所有字符转成大写的\L
将它后面的所有字符转成小写的- 默认情况下,它们会影响之后全部的(替换)字符串,可以用
\E
关闭大小写转换的功能; - 使用小写
\l
和\u
,它们只会影响紧随其后的第一个字符; - 同时使用
\u
与\L
来表示"后续字符全部转为小写的,但首字母大写”
元字符转义
s/\(\(\(Fred/fred/
# 使用\Q简化形式
s/\Q(((Fred/fred/
\
split操作符
- 格式如下:
my @fields = split /separator/, $string;
- 例子如下:
- 注意第二行和第三行
my @fields = split /:/,"abc:def:g:h"; # 得到("abc","def","g","h")
my @fields = split /:/,":::a:b:c:::" # 得到("","","","a","b","c")
my @fields = split /:/,":::a:b:c:::",-1 # 得到("","","","a","b","c","","","")
- 默认
split
会以空白字符分割$_
中的字符串;
my @fields = split; # 基本等效于split /\s+/, $_;
join函数
- join会把胶水涂进每个片段之间并返回结果字符串
my $x = join ":",4,6,8,10,12; # $x 为 “4:6:8:10:12”
my @values = split /:/,$x; # @values 为(4,6,8,10,12)
my $z = join "-", @values; # $z为 “4-6-8-10-12”
列表上下文中的m///
更强大的正则表达式
习题
第10章 其他控制结构
unless控制结构
if
条件为真时执行,unless
条件为假时执行
伴随unless的else语句
- 就是
if else
改成了unless else
until控制结构
- 颠倒while的条件表达式,就用
until
表达式修饰符
- 简化代码书写
- 即使条件表达式写在后面,它也会先执行
- 倒装句
print "$n is a negative number.\n" if $n < 0;
if($n < 0) {
print "$n is a negative number.\n";
}
裸块控制结构
{ }
主要是为变量限制作用域,和c++一样
elsif子句
- 注意不是
elseif
自增与自减
- 前置后置,自增自减。
for控制结构
- 和c语言写法一致
for和foreach之间的秘密
- for和foreach实际上是等价的。括号中有两个分号,就把它当做
for
,若没有分号,就把他当做foreach
循环控制
last操作符
- 和c语言的break一样,退出循环
next操作符
- 和c语言的continue一样,跳过本次循环
redo操作符
- 这不是goto语句封装好的吗?
带标签的块
- 这不就是verilog中的程序块别名吗?
条件操作符
- 三目运算符
? :
expression ? if_true_expr : if_false_expr
逻辑操作符
- 全套的逻辑操作符
短路操作符的返回值
短路操作符
可以改为三目运算符
!
使用部分求值操作符的控制结构
&&
、||
、//
、?:
都是根据左边的值确定要不要执行右边的表达式
习题
第11章 Perl模块
- 如何使用现有的模块,目的是熟悉使用CPAN完成自己的任务!
寻找模块
- 寻找那些没有随Perl发布的模块,可以到CPAN Seach网站(http://search.cpan.org)或MetaCPAN(http://www.metacpan.org)
安装模块
使用简易模块
习题
第12章 文件测试
文件测试操作符
stat和lstat函数
loacltime函数
位运算操作符
习题
第13章 目录操作
当前工作目录
- 借助标准模块之一
Cwd
模块,查看当前的工作目录是哪个
use v5.10;
use Cwd;
say "The current working directory is ",getcwd();
- 可以使用标准模块之一
File::Spec
实现相对路径和绝对路径之间的相互转换\
修改工作目录
chdir
:和shell中的cd一个意思
chdir '/etc' or die "cannot chdir to /etc :$!";
- 可以使用
File::HomeDir
模块去往特定用户的主目录,他支持大部分操作系统。
文件名通配
- 文件名通配:
glob
my @all_file = glob '*';
my @pm_file = glob '*.pm';
- Perl内置的
glob
并非唯一选择,我们可以用File::Glob
模块提供各式兼容和扩展的文件名通配。
文件名通配的隐式语法
my @all_files = <*>; # 效果和这样的写法完全一致: my @all_files = glob "*";
- Perl 会把尖括号内出现的变量替换成它的值,类似于双引号内字符串的变量内插,如下
my $dir = '/etc';
my @dir_file = <$dir/* $dir/.*>;
目录句柄
- 一个例子
my $dir_to_process = '/etc';
opendir my $dh, $dir_to_process or die "Cannot open $dir_to_process:$!";
foreach $file (readdir $dh) {
print "one file in $dir_to_process is $file\n";
}
closedir $dh;
- 使用裸字
DIR
my $dir_to_process = '/etc';
opendir DIR, $dir_to_process or die "Cannot open $dir_to_process:$!";
foreach $file (readdir DIR) {
print "one file in $dir_to_process is $file\n";
}
closedir DIR;
文件和目录的操作
删除文件
unlink
:
unlink 'slate', 'bedrock','lava';
unlink qw{slate bedrock lava};
unlink glob '*.o';
unlink
返回的是成功删除的文件数目,我们可以把他们放到循环依次删除并检查
foreach my $file (qw(slate bedrock lava)) {
unlink $file or warn "failed on $file:$!\n";
}
重命名文件
rename 'old','new';
- 借用胖剪头
=>
: - 如何批量把名称是
.old
结尾的文件改名为以.new
结尾?
foreach my $file (glob "*.old") {
my $newfile = $file;
$newfile =~ s/\.old$/.new/;
if (-e $newfile) {
warn "can't rename $file to $newfile: $newfile exists\n"
} elsif(rename $file => $newfile) {
# 改名成功,什么都不需要做
} else {
warn "rename $file to $newfile failed:$!\n";
}
}
- 循环里的前两行还可以修改为
my ($newfile = $file) =~ s/\.old$/.new/;
- 也可以在Perl 5.14里面加上
/r
修饰符,
use v5.14;
my $newfile = $file =~ s/\.old$/.new/r;
链接与文件
- 与Linux操作系统的文件作对比吧,inode节点等,确定是
软链接
这个说法吗?(之前有老师强调过,没有软链接这一说,是符号链接和硬链接)
创建和删除目录
- 创建失败返回设定值
mkdir 'fred', 0755 or warn "Cannot make fred directory: $!";
- 移除空目录
foreach my $dir(qw{fred barney betty}) {
rmdir $dir or warn "cannot rmdir $dir:$!\n";
}
- 如果要创建临时目录或文件,可以用
File::Temp
模块
修改权限
chmod
不支持linux中a+x
这种格式,除非从CPAN安装了File::chmod
.- 常规格式如下:
chmod 0755, 'fred','barney';
修改文件属主
chown $user, $group, glob '*.o';
修改时间戳
my $now = time;
my $ago = $now - 24 * 60 * 60; # 一天的秒数
utime $now, $ago, glob '*'; # 将最后访问时间改为当前时间,最后修改时间改为一天前
习题
第14章 字符串与排序
用index查找子字符串
my $where = index($stuff, "wor");
用substr操作子字符串
my $part = substr($string,$initial_position, $length);
用sprintf格式化字符串
my $money = sprintf "%.2f", 2.4997;
高级排序
- 飞碟操作符’<=>’
my @descending = sort {$b <=> $a} @some_numbers;
按哈希值排序
my %score = ("barney" => 195, "fred" => 205, "dino" => 30);
my @winners = by_score keys %score;
按多个键排序
- 例子1:
my %score = (
"barney" => 195, "fred" => 205,
"dino" => 30, "bamm-bamm" => 195,
);
my @winners = by_score_and_name keys %score;
sub by_score_and_name {
$score{$b} <=> $score{$a} #先按照分数降序排列
or
$a cmp $b #分数相同的再按名字的ASCII码序排列
} @winners
- 例子2:
@patron_IDs = sort{
&fines($b) <=> &fines($a) or
$items($b) <=> $items($a) or
$family_name{$a} cmp $family_name{$b} or
$personal_name{$a} cmp $family_name{$b} or
$a <=> $b;
} @patron_IDs;
习题
第15章 进程管理
习题
第16章 高级Perl技巧
习题
后记
- 本文内容只是记录了小编想学习的部分,其他部分暂时忽略。
- 要是工作中需要的话,再深究!