Perl 语言入门学习_perl语言学习-程序员宅基地

技术标签: perl  script  

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 + 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 = 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 = "[email protected]"; #这会被perl认为是内插了一个qq的数组,错误的写法
say $email;
$email = '[email protected]'; #使用单引号限制转义,正确的写法
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]#
版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/weixin_43740223/article/details/118698487

智能推荐

Mendix客户项目总结_mendix项目-程序员宅基地

文章浏览阅读983次。​从2005年成立至今,Mendix一直以客户价值为导向精心打磨产品,提升客户、合作伙伴及所有参与方的使用体验。进入中国以来,我们更是以120%的态度践行这一原则。工欲善其事必先利其器,这里的“器”不仅仅在于产品本身,更在于产品背后代表的思维方式,实施合作伙伴的培养与赋能,解决方案架构,项目管理与执行,客户数字化转型的长远的计划与思考等等。只有不断地用先进的理论指导实践,并在实践中迭代成长,才能充分发挥先进生产工具的最大价值,创造多方的共赢局面。因此,我们会建议Mendix客户针对第一期的开发项目认真地_mendix项目

MATLAB修改字体大小,加粗,字体样式,字体颜色,线形,希腊字母,特殊符号,图片文本位置及字体设置等_matlab字体-程序员宅基地

文章浏览阅读2.3w次,点赞41次,收藏255次。MATLAB修改字体大小,加粗,字体样式,字体颜色,线形颜色格式,添加标签,修改标签格式,希腊字母表,图片文本位置等_matlab字体

Spring环境配置(安装springsource-tool-suite插件)及第一个Spring HelloWorld-程序员宅基地

文章浏览阅读3.6k次。SpringSoource-tool-suite安装为了使用Spring的方便,首先Eclipse安装插件SpringSoource-tool-suite(SpringSoource-tool-suite 是一个基于EclipseIDE开发环境中的用于开发Spring应用程序的插件。利用这个插件,可以方便的在Eclipse平台上开发基于Spring框架的应用)。如下是SpringSoource-to_springsource-tool-suite

mysql 效率监控_zabbix监控mysql性能-程序员宅基地

文章浏览阅读156次。通过获取mysql状态值将这些状态值传递给服务器并绘制成图片,这样可以观察mysql的工作情况,通常需要获得状态变量有以下Com_update:mysql执行的更新个数Com_select:mysql执行的查询个数Com_insert:mysql执行插入的个数Com_delete:执行删除的个数Com_rollback:执行回滚的操作个数Bytes_received:接受的字节数Bytes_sen..._zabbix slow queries over 3 for 5m

正交法设计用例_四阶正交拉丁方阵-程序员宅基地

文章浏览阅读4.6k次,点赞3次,收藏14次。正交实验法的由来一、正交表的由来拉丁方名称的由来 古希腊是一个多民族的国家,国王在检阅臣民时要求每个方队中每行有一个民族代表,每列也要有一个民族的代表。数学家在设计方阵时,以每一个拉丁字母表示一个民族,所以设计的方阵称为拉丁方。什么是n阶拉丁方?用n个不同的拉丁字母排成一个n阶方阵(n<26 ),如果每行的n个字母均不相同,每列的n个字母均不相同,则称这种方阵为n*n拉丁方或n阶拉丁方。每个字母在任一行、任一列中只出现一次。_四阶正交拉丁方阵

细粒度情感分析在到餐场景中的应用_absa数据标注工具-程序员宅基地

文章浏览阅读3.6k次。总第482篇2021年 第052篇经典的细粒度情感分析(ABSA,Aspect-based Sentiment Analysis)主要包含三个子任务,分别为属性抽取、观点抽取以及属性-观点..._absa数据标注工具

随便推点

PWA登陆iOS了,但它还有这些缺陷_pwa的缺点-程序员宅基地

文章浏览阅读2.1k次。Apple 在 iOS 11.3 中悄悄加入了对“渐进式 Web 应用”(PWA)这一系列新技术的基本支持。是时候看看这些技术是如何生效的?它有什么能力?会遇到哪些挑战?以及如果已经发布了 PWA,又需要了解哪些事情?本文概括介绍了最新发布的 iOS 11.3 对 PWA 的支持情况,以及 PWA 应用开发者需要注意的问题。本文转载自前端之巅作者 Maximiliano Firtman..._pwa的缺点

Qt 加载图片文件路径详解_qt资源图片路径-程序员宅基地

文章浏览阅读7.6k次,点赞3次,收藏23次。QT 加载文件,图片路径很容易搞混,需要注意的是WINDOW路径分隔符为“\”,QT为“/”,我遇到的路径加载总结为三种情况:(1)绝对路径,文件的整个路径,比如 setWindowIcon(QIcon("F:/QT_PROJECT/QTtest/test/res/123.jpg"));//加载图片绝对路径(2)相对路径 1.第一种情况,新建QT 资源文件,也就..._qt资源图片路径

wanchain是个什么样的项目_wanchain与delphy都是同一个团队的项目吗?你们是不是来圈钱的?-程序员宅基地

文章浏览阅读1.4k次。万维链旨在建立一个分布式的未来“银行”,万维链本身是一个分布式的基于数字资产的金融基础设施,任何机构和个人,都可以在万维链上开设自己的业务窗口,提供基于数字资产的存贷、兑换、支付、结算等服务。更加准确的描述,万维链是一个基于区块链的分布式超级金融市场。_wanchain与delphy都是同一个团队的项目吗?你们是不是来圈钱的?

Linux 系统下搭建 Gitlab 服务器-程序员宅基地

文章浏览阅读2.7k次。1、安装依赖工具// 安装技术依赖yum install -y curl policycoreutils-python openssh-server // 启动ssh服务/设置为开机启动sudo systemctl enable sshdsudo systemctl start sshd2、安装 Postfix 邮件服务器// 安装 postfixsudo yum ins..._linux 安装gitlab服务器

LiveNVR配置拉转RTSP传统海康大华安防摄像机直播流输出RTSP/RTMP/HLS/HTTP-FLV如何获取直播流地址_公网 支持rtsp、http的摄像头-程序员宅基地

文章浏览阅读1.4k次。LiveNVR配置拉转RTSP传统海康大华安防摄像机直播流输出RTSP/RTMP/HLS/HTTP-FLV如何获取直播流地址1、 Onvif/RTSP流媒体服务2、配置拉转直播流2.1 RTSP获取配置规则2.2 编辑通道配置3、接口获取视频流地址3.1、获取通道直播链接接口3.2、获取HTTP-FLV播放地址示例3.3、获取WS-FLV播放地址示例3.3、获取RTMP播放地址示例3.4、获取HLS播放地址示例3.4、获取RTSP播放地址示例4、浏览器F12查看播放地址5、播放页面快速集成1、 Onvif_公网 支持rtsp、http的摄像头

Python 爬取qqmusic音乐url并批量下载_qq音乐源url怎么下载-程序员宅基地

文章浏览阅读1.7k次,点赞3次,收藏13次。使用Python爬虫批量下载音乐_qq音乐源url怎么下载