Perl 语言学习 – 入门篇

入门篇包括但不限于以下内容

  • Perl 简介
  • 版本历史
  • 第一个Perl程序
  • Perl的基本数据类型
  • Perl的运算操作符和判断操作符
  • Perl的数组操作
  • Perl的控制结构语句
  • Perl的子程序

注:尽管本文中没有提及逻辑控制符,但Perl的逻辑控制符与C 或者 JAVA 的逻辑控制符号 基本一致, 都支持与或非的操作 也就是 ! | & 这几个符号,使用上也没有太大差异。因而本文中就此略过,如有需要请自行查阅相关文档

文章目录

  • Perl 语言学习 -- 入门篇
    • 1 Perl 介绍
    • 1.1 Perl 版本
      • 1.1.1 历史版本
      • 1.1.2 主要版本分支 Strawberry Perl 与 ActiveState Perl
      • 1.1.3 CPAN
    • 1.2 Perl 安装
  • 2 第一个Perl程序
  • 3 Perl的数据
    • 3.1 数字
      • 3.1.1 数字运算操作符
      • 3.1.2 数字比较操作符
    • 3.2 字符串
        • 字符串的单双引号区别
      • 3.2.1 字符串运算操作符
      • 3.2.2 字符串比较操作符
      • 3.2.3 字符串的函数操作
      • 3.2.4 数字与字符串的自动运算和类型转换
    • 3.3 布尔值
      • 3.4 变量
      • 3.4.1 变量的赋值
      • 3.4.2 变量的作用域
        • 1.包域全局 our
        • 2.临时全局 local
        • 3.私有局部my
        • 4.持久局部state
    • 3.5 列表和数组
      • 3.5.1 数组
      • 3.5.2 列表
      • 3.5.3 数组和栈Stack
      • 3.5.4 字符串的数组内插
      • 3.5.5 数组的常用函数
  • 4 Perl的控制结构
    • 4.1 判断结构
      • 4.1.1 If 和 unless
    • 4.2 循环结构
      • 4.2.1 while 和 until
      • 4.2.3 foreach 和 for
  • 5 Perl的子程序

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 + 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 字符串的函数操作

  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 = 6my $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
    
  • 如何获取数组的元素 NAME[index]∗∗或者∗∗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 element(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; # 47for $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]#

Perl 语言入门学习相关推荐

  1. c语言10个人 三向成绩,C语言入门学习精华:这样学习C语言最有效

    C语言入门学习精华:这样学习C语言最有效 c语言死了吗? 本材料描述了使用C语言的高级技能,并努力将您的C语言能力从"基本"提升到"高级".然而,学习态度比学习 ...

  2. c语言入门自学免费app,C语言入门学习最新版下载-C语言入门学习app手机版v1.0.2 安卓版-腾飞网...

    C语言入门学习app手机版是一款c语言编程自学软件,零基础也可以学习,里面有海量教学视频,针对c语言不同程度的讲解都囊括其中.随时随地学习编程都可以,不用担心自己没有基础.还支持在手机上敲代码编程哦. ...

  3. 郑州计算机c语言培训机构,c语言入门学习选郑州哪家计算机专业学校

    C语言是一门稀缺的贵族语言,会C语言的被IT界高看,C语言的地位很高,学C语言确实难,但是有正确的方法成为C程序员是非常有效的,会C语言相当于拥有了一定地位,未来非常有前景,那么如何入门C语言呢?选择 ...

  4. c语言入门自学手机版,c语言入门自学app下载-C语言入门学习 安卓版v1.0.2-PC6安卓网...

    C语言入门学习app是一款C语言零基础自学软件.C语言入门自学app提供海量精品学习资源,从小白入门到基础进阶都有,帮你轻松学习编程. 软件介绍 C语言入门学习app是一款专业的编程入门学习App,致 ...

  5. c语言入门自学手机版,C语言入门学习app下载-C语言入门学习app最新版下载 V1.0.2-友情手机站...

    C语言入门学习app是一款0基础自学软件,这里有着丰富C语音相关课程学习,大家在这里是可以便捷搜索查找,随时都是可以找到适合感兴趣课程学习,都是一些优质课程知识提供大家,学员在这里是可以高效学习,海恩 ...

  6. c语言入门自学手机版,C语言入门学习软件下载-C语言入门学习手机版v1.0.2 - 起点软件园...

    C语言入门学习是一款最新推出上线于安卓手机平台的专业编程学习软件,C语言入门学习app收录了海量入门视频课程,清晰易懂的详细讲解专为刚入门学习C语言的小白量身打造,不同章节都有相应的习题,根据习题成绩 ...

  7. R语言入门学习——Rstudio的安装与学习

    R语言入门学习--Rstudio的安装与学习 1.Rstudio下载 2.Rstudio安装 3.Rstudio功能和简单程序 1.Rstudio下载 下载地址:https://rstudio.com ...

  8. lua语言入门学习(二)lua语言的特点及注意事项

    lua语言入门学习 lua语言的特点及注意事项 文章目录 lua语言入门学习 lua语言的学习地址 一.lua语言特点 1.注释 2.全局变量和局部变量 3.lua数据类型 4.字符串类型 5.多变量 ...

  9. lua语言入门学习(一)搭建基本的环境并实现运行

    lua语言入门学习 本篇文章用来记录自己写lua语言的过程 文章目录 lua语言入门学习 前言 一.lua语言是什么? 二.使用步骤 1.搭建环境 2.开始运行 总结 前言 最近来到了一家网络游戏公司 ...

  10. lua语言入门学习(四)项目初体验之抽奖转盘(1)

    lua语言入门学习 今天前辈教我看了项目,感觉果然公司级的项目分工都比较严谨,很多东西都是略懂功能,但对于底层逻辑的实现并不清楚. 为了保护公司这个游戏具体实现功能上本身的隐私,日常代码分享中不会分享 ...

最新文章

  1. ORB_SLAM2代码阅读(5)——Bundle Adjustment
  2. 偶然发现静态函数与性能一例
  3. hdu 7111-Remove
  4. Linux kernel同步机制
  5. 你能打动客户的C++理由,一定要先说服自己相信
  6. odac安装_ODAC安装及环境变量配置
  7. acm 凹多边形面积_解析几何|面积的计算
  8. 图像编码中的小白问题sps ,pps ,nalu ,frame ,silce ect....
  9. 较强冷空气影响中东部地区 江南华南等地有小到中雨
  10. c语言的typedef struct 对应java参数类型,JNA实战系列:02JNA与C语言中的数据类型映射以及复杂结构体传参示例...
  11. python程序输出田字格_Python程序练习题5.1-输出更大的田字格。
  12. linux服务器架设篇 下载_后渗透系列——下载(Windows篇)
  13. DNS大全(114DNS 、阿里DNS、百度DNS 、360 DNS、Google DNS)
  14. html模板生成工具_HTML5模板生成器,框架和工具
  15. 应届生参加工作,什么事情越早知道越好?
  16. Client MFC application解决办法
  17. 历年计算机一级笔试考试真题及答案解析,全国计算机等级考试上机考题全真笔试历年题...
  18. win7计算机本地用户和组,Win7旗舰版找不到本地用户和组如何解决
  19. 杜牧“借问酒家何处有,牧童遥指杏花村”杏花村究竟指的是哪里?安徽的池州比较可靠
  20. SpringBoot+SpringSecurity+JWT整合实现单点登录SSO史上最全详解

热门文章

  1. 地方舆情监测软件排名怎么评估的参考方法详解
  2. [安全攻防进阶篇] 八.那些年的熊猫烧香及PE病毒行为机理分析
  3. 计算机三级数据库技术复习资料总结
  4. sqlserver安装目录_SQL 2008R2安装教程
  5. 免费微信小程序商城源代码,基于Uni-App,实现一码多端
  6. goc 介绍与源代码分析
  7. C 语言是“最环保”的编程语言
  8. 微信小程序下载文件,后端PHP处理流程
  9. Go Web编程(Go语言性能好、语法简单、开发效率高!)
  10. 转载Prince_vegeta制作的VC知识库1-53期合订本索引文件。