Perl 语言学习 – 入门篇
入门篇包括但不限于以下内容
- Perl 简介
- 版本历史
- 第一个Perl程序
- Perl的基本数据类型
- Perl的运算操作符和判断操作符
- Perl的数组操作
- Perl的控制结构语句
- Perl的子程序
注:尽管本文中没有提及逻辑控制符,但Perl的逻辑控制符与C 或者 JAVA 的逻辑控制符号 基本一致, 都支持与或非的操作 也就是 ! | & 这几个符号,使用上也没有太大差异。因而本文中就此略过,如有需要请自行查阅相关文档
1 Perl 介绍
-
Unix系统自带Perl,被称为“Unix工具箱”
-
被称为“实用摘录与报表语言” Practical Extraction and Report Language
-
也被称为“病态这种式垃圾列表器” Pathologically Eclectic Rubbish Lister
-
Perl 座右铭: There’s More Than One Way To Do It !
-
Perl擅长于文本处理和系统管理,不适合于实时嵌入式系统编程、操作系统底层开发(比如驱动程序开发)、复杂的多线性共享内存应用以及极度大的应用。
-
Perl的发明历史
- Larry想为类似新闻组的文件体系写一个Bug汇报系统而发明的**通用的多用途工具**
- 是由C以及sed、awk、Unix shell及其它语言演化而来的一种语言。
- Perl是一种为扫描任意的文本文件,从这些文本文件中获取信息,基于这些信息打印报表而优化的语言。
- 旨在实用(易用、高效、完整)而不是漂亮(优美、小巧)。
-
Perl的特点
- 优点
- 简单好用
- 不受限制
- 不限制数据大小,仅受限于计算机存储
- 几乎所有工作都能用Perl完成
- 性能优秀
- 可移植性:大多数操作系统支持Perl
- 模块扩展
- 函数
- 缺点
- 代码丑(吉祥物是骆驼 -> Useful and ugly)
- 多种语言集合导致的混乱(四不像)
- 可读性差
- 优点
-
一些特点的记忆增强
- Perl程序的长度大约是等效C程序的 30% - 70%
- 适合用于 在三分钟写出“虽然难看但是能用”的一次性程序
- 擅长处理“约有90%与文字处理有关”的问题
尝试用一句话描述Perl
- 这也行?
尝试用一个词描述Perl
- 天马行空
1.1 Perl 版本
1.1.1 历史版本
没有查阅到相关资料,后续补充
1.1.2 主要版本分支 Strawberry Perl 与 ActiveState Perl
- 文件大小不同
- Strawberry Perl:trawberry Perl 下载的安装文件有 80多M。
- Active Perl:ActiveState Perl 只有20M 左右
- 内容不同
- Strawberry Perl:Strawberry Perl 里面有多包含一些 CPAN 里的模块。
- Active Perl:含了包括有 Perl for Win32、Perl for ISAPI、PerlScript、Perl Package Manager四套开发工具程序,可以让用户编写出适用于unix,windows,linux系统的的CGI程序。
- 特点不同
- Strawberry Perl:用于Windows的100%开源Perl,使用来自CPAN的模块不需要二进制包。
- Active Perl:ActiveState提供了一个免费的社区版本和一个商业支持的Perl用于Win32和Perl的二进制分布。
1.1.3 CPAN
Comprehensive Perl Archive Network
Perl综合典藏网 ( http://search.cpan.org/ )
perl 的模块扩展,用于下载基于perl的各种扩展模块及文档资料等。
CPAN也需要额外安装
yum install -y perl-CPAN
cpan的使用同数据库类似,需要进入相应的操作界面, 使用 perl -MCPAN -e shell 进入该操作界面
具体的模块和安装命令后续会聊到。
1.2 Perl 安装
https://www.perl.org/get.html 登录官网下载对应版本安装,打印版本验证安装
perl -v
2 第一个Perl程序
学习过 shell 脚本语言的程序员将会在perl的学习上有所助益。
Perl是一个纯文本文件,可以用任意的文本编辑器来编写Perl程序,例如txt,vm/vim,notepad等
mkdir -p /data/test/
vim /data/test/HelloWorld.pl
键入
#!/usr/bin/perl
print "Hello world!\n";
保存后使用 perl 运行这个文件 。
注:如果使用非管理员用户,请注意当前用户是否有执行权限
perl /data/test/HelloWorld.pl
你可以看到程序会输出相应的字符
继续阅读的一些补充知识点 -> 给刚接触脚本语言的同僚
Perl 的 use 关键字,你在本文的剩余部分会频繁地看到 use 5.014; use warings; use utf8; use strict 等代码,use 关键字实际上是对Perl 程序模块的装载,这是Perl可插拔式编程的关键用法。
上述代码中例如 use 5.014 表示使用 Perl 5 版本号 14 的支持,say 函数在该版本才能够正常使用。
关于use 关键字,还有很多可以展开的,但是现在你只需要记住它被用于引入Perl 程序的模块支持。
关于Perl use 关键字,这里提供一些参考文档:
http://blog.chinaunix.net/uid-608135-id-4439772.html 这里解释了 use 关键字的底层实现和它的用法
http://bbs.eetop.cn/thread-613055-1-1.html 这里提到了 use 关键字 和 require 关键字的执行阶段不同
#!/usr/bin/perl , 你会注意到每一个Perl程序头部的这行字。如果你不熟悉Linux 和脚本语言,也许会对它感到困惑。这是 脚本语言 在 Linux操作系统中的规约,用于告诉操作系统,执行该文件时调用何种解释器。你可以在上面的编写的第一个程序中看到这个区别
这个调用过程指的是 直接运行该脚本文件时,例如
./test.pl
没有任何前缀指向当前文件夹下的test.pl 脚本,操作系统会从第一行声明的解释器路径取查找解释器,用该解释器执行这个脚本。(使用这种方式需要给文件赋予权限)
如果指令编程
perl ./test.pl
显式地声明了执行脚本的解释器,那么头部行没有写也可以。(使用这种方式可以绕过权限限制)
3 Perl的数据
包括以下内容
- 两种基本数据结构(浮点数和字符串)
- 数据的运算和比较操作符
- 浮点数和字符串的类型转换
- 布尔值的定义 undef , 0 , “”
- 变量的赋值及其作用域
- 列表和数组及其赋值
- 列表和数组的常用操作符
- pop
- push
- shift
- unshift
- splice
- reverse
- sort
- each
3.1 数字
Perl内部不存在整数值,所有数字都将被存储为“双精度浮点数”(gcc编译的double类型),
可以直接用整数表示。例如:5 --> 解释为 5.00
注:Perl 内部会使用整数,但编程人员无需关心,其次Perl可以使用integer编译命令编译整数。
Perl 允许在整数中间插入 下划线 _ , 例如表示一个银行卡, 6217_0013_0000_0992_328, 这样看起来就很清楚(如不需要计算,此类数据建议使用字符串表示)
3.1.1 数字运算操作符
Perl支持加减乘除和模运算以及幂运算等
数字运算操作 | 操作符 | 示例 | 示例操作结果 |
---|---|---|---|
加法 | + | 2 + 3 | 5.00 |
减法 | - | 5.1 - 2.4 | 7.50 |
乘法 | * | 1 * 2 | 2.00 |
除法 | / | 14 / 7 | 2.00 |
模运算 | % | 5 % 2 | 1.00 |
幂运算 | ** | 2 ** 3 | 8.00 |
3.1.2 数字比较操作符
数字比较操作 | 操作符 | 示例 | 示例操作结果 |
---|---|---|---|
相等 | == | 1 == 1 | 真 |
不等 | != | 1 != 1 | 假 |
小于 | < | 1 < 1 | 假 |
大于 | > | 1 > 1 | 假 |
小于或等于 | <= | 1 <= 1 | 真 |
大于或等于 | >= | 1 >= 1 | 真 |
关于真假的布尔定义,稍后的章节会说明
3.2 字符串
Perl 的字符串是被单引号’’ 或 双引号 “” 包围的文本,例如: ‘a character’, “still character”;
Perl 的字符串长度无限制。(体现了Perl 原则之一:无内存限制) 0 - Memory-Max
Perl 字符完全支持 Unicode。(需要声明编码格式)
use charset 函数,声明文件的编码格式
encoding(charset) 函数,指定特定行为的编码格式
字符串的单双引号区别
-
单引号 ’ ’
- 单引号中单引号和反斜线 / 字符除外,单引号内所有字符都代表它们本身。
- 要表示反斜线时,需要连续两个反斜线,要表示单引号本身,则将反斜线接着单引号。
-
双引号 " "
- 双引号中转义符 \ 有效,转义符的通常应用如 \n 换行, \r 回车, \u \l 下个字母大小写等等
- 且能够使用$内插一个变量到字符串中
#!/usr/bin/perl
use 5.014;
# 单引号中转义符只能用于转义反斜线本身和单引号
print '\n只是\n';
print "\n";
print '输出一个单引号 \',在输出一个反斜线\\';
print "\n";
# 双引号中转义符\有效,且能够使用$内插一个变量到字符串中
my $sum = 5 + 3;
print "5 + 3 = $sum \n";
print "\uhello \uworld! \n";
3.2.1 字符串运算操作符
. 点可以作为字符串的连接操作符,如下
#!/usr/bin/perl
print "hello " . 'world' . "/n"; # 输出 hello world [换行符]
x 操作符可以重复输出相同的字符,如下
重复次数在使用前会先取整,去掉小数位,重复次数小于等于0时,生成空字符串
#!/usr/bin/perl
print "perl " x 3; #输出 perl perl perl
print "perl " x 2.8; #输出 perl perl
print "perl " x 0; #输出 [空字符串]
两者可以结合使用, 例如
#!/usr/bin/perl
print "perl " x 3 . "\n"; #输出 perl perl perl [换行符]
3.2.2 字符串比较操作符
同样支持六种比较操作,但符号与数字不相同。
字符比较操作 | 操作符 | 示例 | 示例操作结果 |
---|---|---|---|
相等 | eq | “a” eq “a” | 真 |
不等 | ne | “35” ne “35.0” | 真,按照字符比较 |
小于 | lt | “b” lt “a” | 真, 按照字母顺序表 |
大于 | gt | “aa” gt “a” | 真, 按照字符长度 |
小于或等于 | le | “aa” le “aa” | 真 |
大于或等于 | ge | “aa” ge “aa” | 真 |
3.2.3 字符串的函数操作
-
index 查找子字符串
基本格式: index($STRING, matchString, [start_index])
- $STRING 必选: 要查找的目标字符串
- matchString 必选: 要查找的字符
- start_index 非必选 :从目标字符串的何处下标开始查找匹配
查找指定字符串在目标字符串中的相对位置,返回匹配到的下标值, 未匹配到则返回 -1
#!/usr/bin/perl my $stuff = "hello world"; my $where = index $stuff, "world"; # $where = 6 my $where1 = index $stuff, "l"; # $where1 = 2 my $where2 = index $stuff, "l", $where1 + 1; # $where2 = 3 my $where3 = index $stuff, "l", $where2 + 1; # $where3 = 9 my $where4 = index $stuff, "l", $where3 + 1; # $where4 = -1
-
substr 截取字符串
基本格式: substr($STRING, start_index, [sub_length])
- $STRING 必选 :目标字符
- start_index 必选: 开始截取的字符串下标
- sub_length 非必选: 截取长度
目标字符串被截取后并不会有任何变化
#!/usr/bin/perl use 5.010; my $str = "I solemnly swear that I am up to no good" my $ret1 = substr $str, 20; # $ret1 = I am up to no good say $ret1 . "\n" . $str; # $str还是等于原文 my $ret2 = substr $str, -4, 4; # $ret2 = good say $ret2 . "\n" . $str; # $str还是等于原文
-
printf 和 sprintf格式化字符串
基本格式:printf(pattern, $String…)
- pattern 必选 : 格式化语句,以 % 开头的字符,每个%号对应一种格式,同时将对一个参数进行格式化
- $String… 必选 : 要格式化的目标字符,可能有多个,与pattern格式化语句的个数相对应
基本格式:sprintf(pattern, $String…)
printf 与 sprintf有相同的参数和句柄,printf将直接把字符经过格式化后打印到命令行,而sprintf将返回格式化后的字符而不进行打印
printf 同java的格式化输出和C的格式化输出基本是一致的。
#!/usr/bin/perl # %g 表示按需要自动选择浮点数、整数或者指数形式 # 2.5 3 1.0683e+29 printf "%g %g %g\n", 5/2, 51/17, 51**17; # %d 表示十进制整数格式,将自动去掉小数点后的数字 # 2 printf "%d\n", 2.5; # %6d 6表示定长字符,在输出日志等消息时频繁使用 # ······2 (·表示空格) printf "%6d\n", 2;
3.2.4 数字与字符串的自动运算和类型转换
运算操作符决定数字与字符串的结合产物,使用数字操作符连接则所有被连接的变量作为数字,使用字符操作符连接则被连接的变量被视为字符,如下所示
#!/usr/bin/perl
use 5.014;
say "1" + 2; #输出3
say "1" . 2; #输出12
say "1" x 3 + 2; #输出113 重复字符次数先运行
say "1" . 3 + 2; #输出15 加法先运行
say "1" x 3 * 2; #输出222 重复字符次数先运行
say "1" . 3 * 2; #输出16 乘法先运行
注:
操作符优先级,参考文档,常用的如右侧所示: () 高于 ++ – 高于 * / % x 高于 + - .
字符自动转换数字规则,首字符如果不为数字,则视为0,反之则取数字,直到匹配到不为数字的字符。如:
12kjsdha2321 会被视为 数字 12。
lksjdlak123 会被视为 数字 0。
代码演示
#!/usr/bin/perl use 5.014; say "ksjdhalkd23" * 12; # 输出 0 say "12ioqwnk3354" * 2; # 输出24
3.3 布尔值
Perl 没有明确的两个标量值来定义真假
关于真假的定义是以假来定义的,下面这些都是假的值,除此之外,其他值都为真值
- undef - 表示未定义的值.
- 0 - 数字0,即使你写成000或者0.0也同样.
- ‘’ - 空字符串.
- ‘0’ - 只包含一个0字符的字符串.
如下示例
#!/usr/bin/perl
use 5.014;
# 0为假
if(!0) {
say "hello";
}
# 空字符为假
if(!"") {
say "world";
}
# 任何非空的字符都为真
if('asdjkhasdk') {
say "anyway";
}
# 任何非0的数字都为真
if(5646545) {
say "everything is ok";
}
# undef 是假
if(undef == 0) {
say "undefined == false "
}
3.4 变量
指存储值的容器,同其他编程语言的变量。
使用 $ 声明一个变量
命名区分大小写,字母或下划线_开头,可以由大小写字母,数字,下划线构成。
#!/usr/bin/perl
$variable1 = 1; #声明一个数字变量
$usr_variable = 1; #使用下划线连接多个单词的变量
$usrVariable = 1; #使用驼峰命名法
$USER_VARIBALE_CONSTANT = 1; #!!!不建议使用全大写的,可能与Perl保留的特殊变量名称冲突
3.4.1 变量的赋值
使用 = 号连接 变量 和 标量完成赋值
#!/usr/bin/perl
$variable = "value";
字符变量和数字变量的操作符与标量相同,此外还支持双目赋值操作符
如下所示
#!/usr/bin/perl
use 5.014;
# 加等于操作
my $num1;
$num1 = $num1 + 1;
$num1 += 1;
say $num1;
# 输出2 0 + 1 + 1 = 2
# 减等于操作
my $num2;
$num2 = $num2 - 1;
$num2 -= 1;
say $num2;
# 输出 -2 0 - 1 - 1 = -2
# 乘等于操作
my $num3 = 1;
$num3 = $num3 * 2;
$num3 *= 2;
say $num3;
# 输出4 1 * 2 * 2 = 4
# 除等于操作
my $num4 = 1;
$num4 = $num4 / 2;
$num4 /= 2;
say $num4;
# 输出0.25 1 / 2 / 2 = 0.25;
# .等于操作(连接字符)
my $str1 = "one_";
$str1 = $str1 . "two_";
$str1 .= "three";
say $str1;
# 输出 one_two_three;
# x等于操作(字符串的重复次数操作)
my $str2 = "yo ";
$str2 = $str2 x 2;
$str2 x= 2;
say $str2;
# 输出 yo yo yo yo;
3.4.2 变量的作用域
转载自 https://blog.csdn.net/henjay724/article/details/8457556#
考虑到示例不能完全体现关键字的主要作用和区别,对转载的内容中示例部分做了修改
由于原文有部分内容错误,这里也做出了修改。例如local不能声明一个新的变量,这里经过实验是可以,因而删除。此外还添加了部分内容以补充。
知识点概要:
-
变量范围分为两类:全局、局部
-
全局变量标准(our)关键字、局部私有变量(my)关键字
-
局部本地变量(local)关键字、持久性私有变量(state)关键字
在Perl中,所有的变量、子程序和其他可以被命名的实体默认都拥有包作用域(亦称“全局作用域”),也就是说它们存在于当前包的符号表中。可以在脚本文件中通过package 函数声明包名
package myPack;
如果不声明包名,则默认为main包。
如果没有关键字声明变量,Perl会默认变量为全局变量,但如果启用了 use strict 指令强制规定,则Perl会强制要求必须先声明变量后才可使用变量。
1.包域全局 our
our操作符用于显式地创建包作用域变量。
#!/usr/bin/perl
use 5.010;
# 关键字our
sub subroutine1{
say $var; #得到全局的var变量
$var +=1;
say $var;
&subroutine2;
}
sub subroutine2{
$var +=1; #得到全局的var变量
say $var;
}
our $var =1; #全局, 作用域为包
&subroutine1; #输出1\n 2\n 3\n
say $var; #输出3\n
注1:our操作符是在Perl 5时代被引入的,Perl 4时代变量均为全局,且不需声明。到了Perl 5时代为避免变量混乱,引入了use strict指令强制规定必须声明变量,而our操作符就是定义了一个看起来像词法作用域的全局变量,从而通过strict指令限制。
注 2 :如果全局变量已存在,则 our 的作用是声明这个全局变量(类似于 C 中的 extern )。
2.临时全局 local
local 修饰一个变量使其作为一个局部变量在该子程序域内有效,且与my不同,其可以继续传递到该子程序内部调用的其他子程序内,产生一个传递的效果。
#!/usr/bin/perl
use 5.010;
# 关键字local
sub subroutine0{
my $var = 100; #声明局部var变量,此时打印将得到局部变量
say $var;
&subroutine1;
}
sub subroutine1{
say $var; #my变量作为私有变量不能传递到其调用的子程序内,此时得到全局变量
local $var = 5; #临时全局变量, 作用域为子程序内部
say $var;
&subroutine2;
}
sub subroutine2{
$var +=1; #local变量将继续传递到其调用的子程序内部
say $var;
}
our $var =1; #全局, 作用域为包
&subroutine0; #输出100\n 1\n 5\n 6\n
say $var; #输出1\n
注 1 : local 变量是在运行时起作用,它会将参数的值保存在一个运行栈中,当执行线程离开所在作用域时,原先作用域暂存的变量会被恢复。
注2 : local和my都只在一个限定的代码块内生效,但是local的变量可以继续在这个代码块中调用的子程序中存在。
3.私有局部my
虽然local操作符的历史比my操作符久远,但Perl后来还是新增了my来分担local的工作,在大部分情况下应首选my,但也有一些特殊情况下必须使用local。
my操作符用于创建词法作用域变量,通过my创建的变量,存活于声明开始的地方,直到闭合作用域的结尾。
闭合作用域指的可以是一对花括号中的区域,可以是一个文件,也可以是一个eval字符串。
#!/usr/bin/perl
use 5.010;
# 关键字my
our $var =1; #全局变量,作用域为包
sub subroutine0{
my $var =2; #私有局部变量, 作用域为花括号
$var +=1;
say $var;
&subroutine1;
}
sub subroutine1{
say $var; #my私有变量不能传递到其调用的子程序内,仍然读取到全局变量
}
&subroutine0; #输出3\n 1\n
say $var; #输出1\n
注1:my是编译时在私有符号表中创建新变量,这个变量在运行时无法使用名字进行独立访问,即它不存在于包符号表中(非全局)。
注 2 :当闭合作用域里的 my 变量与外层变量重名时,当前 my 变量有效,当退出作用域时,外层变量值不变。
4.持久局部state
使用state操作符来声明变量,可以在子程序的多次调用期间保留变量之前的值,并将变量的作用域局限于子程序内部。
#!/usr/bin/perl
use 5.010;
# 关键字state
sub subroutine0 {
state $var =2; #持久局部变量, 作用域为子程序内部
$var += 1;
say $var;
&subroutine1;
}
sub subroutine1 {
say $var; #由于state变量和my变量都无法传递,因而这里输出空字符串
}
my $var = 1; #局部变量,作用域当前脚本文件
&subroutine0; #输出3\n 空字符串\n
&subroutine0; #输出4\n 空字符串\n
#这里输出4说明state在其作用域内上次操作的值得以保存
say $var; #输出1\n
注1:state 修饰的变量在退出子程序后将失效,要理解多次调用期间保留变量之前的值的含义是局限在作用域内的。
注2:state是从Perl 5.10开始引入的,所以使用前必须加上use 5.010或更高版本指令。
注 3 : state 可以声明标量、数组、哈希。但在声明数组和哈希时,不能对其初始化(至少 Perl 5.14 不支持)。
3.5 列表和数组
- 列表 指多个值的有序集合, 数组 则相对应是存储列表的变量
3.5.1 数组
数组指存储列表的变量,每一个数组都包含一个列表。
基本格式: arrays[0] = 1; $element = arrays[0]; $element = arrays[-1];
-
如何声明一个数组 $NAME[index] = value
概要
-
数组下标指向一个标量即完成声明
-
下标为0的元素为数组的第一个元素
-
若声明的数组下标指向一个大于0的数,则自动扩充其和第一个元素之间的所有元素,扩充的元素默认为undef
#!/usr/bin/perl $arr1[0] = 1; #声明一个数组arr1,并对其第一个元素赋值 $arr1[1.564] = 2; #自动去除小数点 等效于 $arr1[1] = 2; $arr222[99] = 100;#声明一个数组arr222,并对其第100个元素赋值,其余99个元素值都为undef
-
-
如何获取数组的元素 N A M E [ i n d e x ] ∗ ∗ 或 者 ∗ ∗ NAME[index]** 或者 ** NAME[index]∗∗或者∗∗NAME[index的负数]
概要
- $数组下标获得一个数组元素
- 如果该数组下标不存在,返回一个undef
- 可以以负数为下标取值,即下标倒数,从-1开始
#!/usr/bin/perl use 5.010; $arr[0] = 'a'; $arr[1] = undef; $arr[2] = "b"; my $value = $arr[0]; #获得数组的第一个元素 'a' my $value = $arr[999999]; #如果超过数组下标最大长度,不会导致错误,只是得到一个undef值 my $value = $arr[$#arr];#获得数组最后一个元素 "b" my $value = $arr[-1]; #获得数组最后一个元素 "b" my $value = $arr[-2]; #获得数组倒数第二个元素 undef my $value = $arr[-3]; #获得数组倒数第三个元素也就是第一个元素 'a' my $value = $arr[-4]; #超过了数组的下标,得到undef值
-
如何获取数组的长度
概要
- $#ARRAYS_NAME(数组最后一个元素下标) + 1
#!/usr/bin/perl $arr[9] = 10; my $len = $#arr + 1; # $#arr = 9, 9 + 1 等于 10; $arr[$#arr] = 10; # 因此可以通过这种形式修改获得得到数组的最后一个值,但是要在数组被声明的前提下,否则将导致错误
3.5.2 列表
列表,列表在程序中表示一列数据。其与数组的关系如同比 值与变量的关系 一样,一个作为数据,一个作为存储数据的容器或者说引用。
-
如何表示一个列表?
#!/usr/bin/perl (1, 2, 3) # 包含三个数字元素的列表 (1.25, "str") # 包含两个元素的列表 ($var1, $var2) # 列表中也可以存储变量 (1..100) # 列表中可以使用.. 链接数字,其表示包含 1 - 100 的一百个数字 qw(windows linux ubuntu) #quoted world简写,等效于('windows', 'linxu', 'ubuntu'), 是快速声明字符列表的一种简写方式,注意其声明的是单引号的字符,因而不支持字符的转义 qw|(ios) (andorid) (harmonyOS)| #另外一个qw简写写法,qw简写可以使用不同的符号作为分界符,具体原因如该例中的写法,由于文本本身有括号,再使用括号就无法正确分界。该例等效于('(ios)', '(andorid)', '(harmonyOS)') qw<1 2 3> #qw简写中,定界符也可以使用其他明确定义的左右符号,例如{}<>()[]。该例等效于('1','2','3')
-
列表如何赋值到变量\数组中?
@数组名 , 将表示整个数组,如下,假设该数组只有下标 0 - 2 三个元素
for e l e m e n t ( element ( element(arr[0], $arr[1], $arr[2]) {} 等效于 for $element (@arr) {}
#!/usr/bin/perl ($var1, $var2, $var3) = (1, 2, 3, 4, 5); # 列表可以直接赋值到变量中,相当于分别给三个变量赋值,多余的元素会被忽略,如果参数不足,则赋予undef值 ($var1, $var2) = ($var2, $var1); # perl中快速交换两个变量值的方法 ($arr[0],$arr[1],$arr[2]) = qw[狮子 斑鬣狗 花豹 野犬 猎豹 胡狼]; # 给数组下标 0 - 2 的元素赋值,多余的两个字符会被忽略 @arr = ('狮子', '斑鬣狗', '花豹', '野犬', '猎豹', '胡狼'); # 将列表中的元素赋值到数组中,从下标0开始 @arr = qw[狮子 斑鬣狗 花豹 野犬 猎豹 胡狼]; # 将列表中的元素赋值到数组中,从下标0开始, 这里比较上述两例,可以看到qw简写和@符号的使用 @copy = @arr; # 复制一个数组
3.5.3 数组和栈Stack
栈 pop push操作
Perl的数组支持栈Stack 的操作,关于栈结构,可以简单理解为一个先入后出的列表,其中入的操作称为push,出的操作称为pop。
#!/usr/bin/perl
use 5.010;
@arr = 1..10;
say $#arr + 1; # 10
@var = pop(@arr); #出栈操作1
say $#arr + 1; # 9
$val = pop @arr; #出栈操作2
say $#arr + 1; # 8
pop @arr; # 出栈也可以不使用出栈的数据
say $#arr + 1; # 7
push(@arr, 11); #入栈操作1
say $#arr + 1; # 8
push @arr, 12; #入栈操作2
say $#arr + 1; # 9
push @arr, 13..20; #批量的数字入栈
say $#arr + 1; # 17
push @arr, qw[a b c d]; #批量的字符入栈
say $#arr + 1; # 21
@newarr = 'a'..'z';
push @arr, @newarr; #其他数组的数据批量入栈
say $#arr + 1; # 47
for $var (@arr) {
print $var . " ";
}
say;
栈 shift 和 unshift操作
pop和push针对的是数组尾部的元素,而shift和unshift针对的是数组头部的元素,用法一致,不多做解释
#!/usr/bin/perl
@arr = 1..10;
$var = shift @arr;
unshift @arr, 'newElement';
splice 移接操作
基本格式([]表示可选参数): [@RECEIVE_ARR] = splice @ARR_NAME start_index [splice_number] [replace_list]
分别对每一个参数做解释
- @RECEIVE_ARR 可选的 :splice操作返回一个数组,即源数组中被移除的部分,@RECEIVE_ARR 用于接收返回值
- splice 必选的: 操作符本身
- @ARR_NAME 必选的:源数组本身
- start_index 必选的:移除操作开始的下标
- splice_number 可选的:移除的元素个数,默认为 $#ARR_NAME(数组最后一个元素) - start_index + 1;
- replace_list 可选的:在移除操作后,将该列表添加到源数组中,可以是一个其他的数组,或者一个列表直接量
代码示例如下
#!/usr/bin/perl
use 5.010;
@arr = 'a'..'z'; # a - z 26个字母
@removed = splice @arr, 14; #移除下标14以后的所有元素
say "first removed : @removed"; #输出第一次移除的元素 o - z
@removed = splice @arr, 0, 7; #移除下标0之后7个元素
say "second removed : @removed"; #输出第二次移除的元素 a - g
@removed = splice @arr, 0, 7, 1..10; #移除下标0之后7个元素,然后补充1 - 10 10个数字元素
say "the third time removed : @removed"; #输出第三次移除的元素 h - n 注意第二次移除后元素下标的重新调整
say "current arr : @arr";
3.5.4 字符串的数组内插
数组可以使用@符号直接内插到字符串中,同$变量的内插一样,但也导致了@符号的使用限制,需要在实际编写脚本时注意
例如
#!/usr/bin/perl
use 5.010;
@arr = 1..10;
$str = "countdown: @arr";
say $str;
# email 和数组内插的 符号冲突问题解决
$email = "[email protected]"; #这会被perl认为是内插了一个qq的数组,错误的写法
say $email;
$email = '[email protected]'; #使用单引号限制转义,正确的写法
say $email;
$email = "11111\@qq.com"; #手动转义,比较麻烦,也是正确的写法
say $email;
3.5.5 数组的常用函数
-
reserver反置数组
基本格式:reverse arraysOrList
- arraysOrList 必选: 要反置的数组或列表直接量
#!/usr/bin/perl my @numbers = 1..10; # 元素为 1 - 10的数组 my @countdownNumbers = reverse @numbers; # 元素为 10 - 1 的数组 my @countdownNumbers2 = reverse 1..10; # 元素为 10 - 1 的数组
-
sort 数组排序
基本格式:sort arraysOrList
- arraysOrList 必选: 要进行排序的数组或列表直接量
根据内部的字符编码顺序对元素进行排序
#!/usr/bin/perl use 5.010; @words = qw [b a g c d f e]; # 乱序字母 @sortedWords1 = sort @words; # 排序后 a b c d e f g @sortedWords2 = sort qw /b a g c d f e/; # 效果与上例相同 say "@words\n@sortedWords1\n@sortedWords2";
-
each 数组遍历
基本格式:($index, $value) = each @array
- $index 必选 : 当前元素下标
- $value 必选 : 当前元素值
- @array 必选 : 遍历的数组
没次each数组,将返回一组键值对,键为数组元素的下标,值为数组元素的值。
实际上,在有了foreach后,each显得不那么好用,除非你需要针对数组下标进行一些编程,否则使用foreach可能更加方便
each 语法需要 5.012以上版本支持
#!/usr/bin/perl use 5.012; my @fruits = reverse sort qw <banana orange watermelon apple>; # 使用each函数遍历数组 while (my($index, $value) = each @fruits) { say "current element = $index:$value"; } # 使用数组下标foreach遍历数组 foreach my $index (0.. $#fruits) { say "current element = $index:$fruits[$index]"; } # 使用for循环遍历数组 for(my $index = 0; $index <= $#fruits; $index += 1) { say "current element = $index:$fruits[$index]"; }
4 Perl的控制结构
包括以下内容
- 判断控制结构(if[else], unless[else])
- 循环控制结构 (while, until, forEach, for)
- 循环控制操作符(last next redo)
- 循环体的标签使用(LABEL)
4.1 判断结构
4.1.1 If 和 unless
unless 就是反if ,但相较于if,unless不仅在语义上有点反人类,而且缺少elsif多重判断支持,因而一般使用if即可。
代码示例
#!/usr/bin/perl
use 5.014;
#使用if判断
foreach (1..10) {
my $value = (int rand 10); # 生成一个0 - 9 的随机整数
if ($value == 0) {
# 当条件为真,进入代码块
say "$value";
} elsif($value % 2 == 0) {
say "$value 是个非零偶数";
} else {
say "$value 是个奇数";
}
}
say "-------------分界线-------------";
#使用unless判断
foreach(1..10) {
my $value = (int rand 10);
unless ($value % 2 == 0) {
# 当条件为假,进入代码块
say "$value 是个奇数";
} else {
say "$value 是个偶数";
}
}
4.2 循环结构
4.2.1 while 和 until
while 语句中当条件为真时循环执行代码块,
until 与之相反,两者在语义上皆符合人类语言的理解,因而使用哪一种都是可以的。
当条件为真,将持续执行代码块, 如下示例将依次打印 2 4 6 8 10 两遍
#!/usr/bin/perl
$count = 0;
while($count < 10) {
#当count小于10时
$count += 2;
print "$count\n";
}
print "-------------分界线-------------\n";
$count = 0;
until($count >= 10) {
#直到count>=10
$count += 2;
print "$count\n";
}
4.2.3 foreach 和 for
for和foreach很大程度上能够混用,这个可以在实际编程过程中,选择自己最喜欢的写法
针对数组变量或者列表的遍历操作,如下三例都将一次打印 1 - 10
#!/usr/bin/perl
@number = 0;
@numbers = 1..3;
foreach $number (@numbers) {
print "$number\n";
}
for $number (@numbers) {
print "$number\n";
}
for $number (1..3) {
print "$number\n";
}
for (qw[1 2 3]) {
print "$_\n"; #注意这例中没有控制变量,而是使用 $_ ,这是perl的默认变量。这种写法也是允许的
}
use 5.010;
for (qw[google apache microsoft]) {
say; #这里相当于 say "$_";
}
for($int = 0; $int < 5; $int += 1) {
say $int;
}
注:
- 上例中number作为foreach循环的控制变量,在循环开始前是有值的,那么它将在每一次循环结束后恢复到原来的值 0 。
- 关于$_ $_是perl中的默认变量,在很多单个参数的场景中被使用,包括循环/判断结构以及各类函数中,具体可以参考https://cn.perlmaven.com/the-default-variable-of-perl,并试试其中的写法
5 Perl的子程序
perl 也支持类似C的函数功能对程序进行进一步的封装,子程序的基本格式为
sub 子程序名 {
#这里书写子程序的程序主体
}
子程的调用使用 & 符号 或者在程序名后加() 进行调用
&子程序名;
子程序名();
# 带参数的子程序调用
&子程序名($param1, $param2);
子程序名($param1, $param2);
上述中子程序含参数时,子程序如何获取这些参数呢?perl并没有显式地定义子程序参数地地方。这个时候就可以使用perl的默认参数 $_
#!/usr/bin/perl
use 5.010;
sub mySubroutine {
for $index (0..$#_) {
#从0开始到 $_ 参数的最后一个下标
say "参数$index 值为: $_[$index]";
}
# 更直观一点
say "第一个参数 = $_[0]";
say "第二个参数 = $_[1]";
}
mySubroutine("Hello Subroutine", 2021);
说完程序的参数后,基于我们以往的编程经验,我们很容易联想到返回值的问题,程序的返回值如何定义,如何接收呢?实际上,在子程序执行过程中,最后一次运算的结果将作为子程序的返回值,程序自动识别而不需要你显式地使用类似return关键字进行返回,当然了,你也可以直接使用return返回某个值以结束子程序
代码示例
#!/usr/bin/perl
use 5.010;
sub mySubroutine0 {
"Hello subroutine";
}
sub mySubroutine1 {
}
sub mySubroutine2 {
return "read paramter" if @_ > 0; #如果参数列表大于0,直接返回值
"Hello subroutine";
}
$ret0 = mySubroutine0();
$ret1 = mySubroutine1();
$ret2 = mySubroutine2(1); #传入一个参数
say $ret0; # 输出 Hello subroutine
say $ret1; # 输出 空串
say $ret2; # 输出 read paramter
更多的示例代码如下所示:
#!/usr/bin/perl
use 5.014;
# 声明无返回值的子程序
sub not_ret_func {
# 实际上是有返回值的,最后一行将print函数将返回成功执行的代码1
# 这个返回值通常作用大多数指令的成功执行标志
# 个别场景下会借以进行条件判断
print "hello world \n";
}
# 声明无返回值的子程序
sub has_ret_func {
# 最后一个值是返回值
my $test = "return value";
$test;
}
# 调用
my $ret1 = ¬_ret_func;
say 'func1 return = ' . $ret1 . " func2 return = " . &has_ret_func;
# 声明含参数的子程序
sub has_param_func {
# 默认数组参数$_ 作用子程序的参数列表
$_[0] + $_[1];
}
# 调用含参子程序
my $num1 = 1;
my $num2 = 2;
say $num1 . ' + ' . $num2 . ' = ' . &has_param_func($num1, $num2);
输出如下
[root@localhost test]# chmod 447 sub.pl
[root@localhost test]# ./sub.pl
hello world
func1 return = 1 func2 return = return value
1 + 2 = 3
[root@localhost test]#
``perl
#!/usr/bin/perl
use 5.010;
sub mySubroutine0 {
“Hello subroutine”;
}
sub mySubroutine1 {
}
sub mySubroutine2 {
return “read paramter” if @_ > 0; #如果参数列表大于0,直接返回值
“Hello subroutine”;
}
$ret0 = mySubroutine0();
$ret1 = mySubroutine1();
$ret2 = mySubroutine2(1); #传入一个参数
say $ret0; # 输出 Hello subroutine
say $ret1; # 输出 空串
say $ret2; # 输出 read paramter
[外链图片转存中...(img-62W9inoS-1626155603241)]
更多的示例代码如下所示:
```perl
#!/usr/bin/perl
use 5.014;
# 声明无返回值的子程序
sub not_ret_func {
# 实际上是有返回值的,最后一行将print函数将返回成功执行的代码1
# 这个返回值通常作用大多数指令的成功执行标志
# 个别场景下会借以进行条件判断
print "hello world \n";
}
# 声明无返回值的子程序
sub has_ret_func {
# 最后一个值是返回值
my $test = "return value";
$test;
}
# 调用
my $ret1 = ¬_ret_func;
say 'func1 return = ' . $ret1 . " func2 return = " . &has_ret_func;
# 声明含参数的子程序
sub has_param_func {
# 默认数组参数$_ 作用子程序的参数列表
$_[0] + $_[1];
}
# 调用含参子程序
my $num1 = 1;
my $num2 = 2;
say $num1 . ' + ' . $num2 . ' = ' . &has_param_func($num1, $num2);
输出如下
[root@localhost test]# chmod 447 sub.pl
[root@localhost test]# ./sub.pl
hello world
func1 return = 1 func2 return = return value
1 + 2 = 3
[root@localhost test]#
文章评论