Perl 语言入门学习

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

你可以看到程序会输出相应的字符

在这里插入图片描述

继续阅读的一些补充知识点 -> 给刚接触脚本语言的同僚

  1. 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 关键字的执行阶段不同

  2. #!/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 + 35.00
减法-5.1 - 2.47.50
乘法*1 * 22.00
除法/14 / 72.00
模运算%5 % 21.00
幂运算**2 ** 38.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 字符串的函数操作

  1. 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
    
  2. 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还是等于原文
    
  3. 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  乘法先运行

注:

  1. 操作符优先级,参考文档,常用的如右侧所示: () 高于 ++ – 高于 * / % x 高于 + - .

  2. 字符自动转换数字规则,首字符如果不为数字,则视为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不能声明一个新的变量,这里经过实验是可以,因而删除。此外还添加了部分内容以补充。

知识点概要

  1. 变量范围分为两类:全局、局部

  2. 全局变量标准(our)关键字、局部私有变量(my)关键字

  3. 局部本地变量(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

    概要

    1. 数组下标指向一个标量即完成声明

    2. 下标为0的元素为数组的第一个元素

    3. 若声明的数组下标指向一个大于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的负数]

    概要

    1. $数组下标获得一个数组元素
    2. 如果该数组下标不存在,返回一个undef
    3. 可以以负数为下标取值,即下标倒数,从-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值
    
  • 如何获取数组的长度

    概要

    1. $#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 = "11111@qq.com"; #这会被perl认为是内插了一个qq的数组,错误的写法
say $email;
$email = '11111@qq.com'; #使用单引号限制转义,正确的写法
say $email;
$email = "11111\@qq.com"; #手动转义,比较麻烦,也是正确的写法
say $email;

在这里插入图片描述

3.5.5 数组的常用函数

  1. 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 的数组
    
  2. 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";
    
  3. 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;
}

在这里插入图片描述

注:

  1. 上例中number作为foreach循环的控制变量,在循环开始前是有值的,那么它将在每一次循环结束后恢复到原来的值 0 。
  2. 关于$_ $_是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 =  &not_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 =  &not_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]#
  • 41
    点赞
  • 381
    收藏
    觉得还不错? 一键收藏
  • 7
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值