1 标量数据:
Perl用标量(scalar)来称呼单个事物。
(1)浮点数直接量:1.25 7.25e24
(2)整数直接量:12 -40
注:Perl里面允许你在整数直接量中插入下划线,将若干位数分开:54_5545_4966_6344
在这里不要使用逗号,因为逗号在 Perl里面已经有更重要的用途
(3)非十进制的整数直接量(也允许使用下划线)(前置零写法)
八进制直接量以0开头,十六进制直接量以0x开头,二进制直接量则以0b开头
0377 = 255
0xff = 255
0b11111111 = 255
2 字符串
Perl完全支持Unicode,但是需要手工加上utf8编译指令
use utf8;
(1) 单引号内的字符串直接量
除了单引号和反斜线字符外,单引号内所有字符都代表它们自己
单引号内的\n并不是换行符,而是表示字面上的两个字符:反斜线和字母n
只有在反斜线后面接续单引号或者反斜线时,才表示转义
(2) 字符串操作符
连接符:.
"hello" . ' ' . "world"
字符串重复操作符:
小写字母x
"hello" x 3 hellohellohello
5 x 4.8 本质就是5 x 4 5555
"前置零"的技巧只对直接量有效,不能用于字符串的自动转换,自动转换总是按照十进制数字来处理的。
0377 = 255
'0377' 会转换成十进制数字377
3 Perl的内置警告信息
从Perl 5.6开始,我们可以通过编译指令开启警告功能
use warnings;
也可以在命令行使用-w选项对要运行的程序开启警告功能
perl -w 脚本文件
如果需要更加详细的问题描述,请使用
use diagnostics; --速度会变慢
注:告警不会改变程序的行为,只是抱怨几声而已
优化,通过perl的命令行选项-M来实现
perl -Mdiagnostics 脚本
4 标量变量
(1) 借助代码点创建字符
chr()函数:将字符的代码点转换成对应的字符
ord()函数:将字符转换为代码点
E 比较操作符
比较 数字 字符串
相等 == eq
不等 != ne
小于 < lt
大于 > gt
小于或等于 <= le
大于或等于 >= ge
特殊几个例子:
35 == 35.0 True
' ' gt '' True
'35' == '35.0' False
F 布尔值
Perl里面其实没有专门的"布尔值"数据类型,规则如下:
如果是数字,0为假;所有其他数字都为真
如果是字符串,空字符串('')为假,所有其他字符串都为真
如果既不是数字也不是字符串,那就先转换成数字或者字符串再进行判断
注:字符串'0'跟数字0是同一个标量值,所以Perl会将字符串'0'唯一当成假的非空字符串。
5 获取用户输入
$line = <STDIN>;
if ($line eq "\n")
{
print "That was just a blank line!\n";
}
else
{
print "That line of input was: $line";
}
<STDIN>返回的字符串一般在末尾都会带有换行符。
6 chomp操作符
chomp() 只能作用于单个变量,且该变量的内容必须为字符串
如果该字符串末尾是换行符,chomp()的任务就是去掉它
常见用法:
chomp($text = <STDIN>);
chomp函数的返回值是实际移除的字符数。
$food = <STDIN>;
$betty = chomp $food; 可以不加括号
如果字符串后面有两个以上的换行符,chomp()仅仅删除一个,如果结尾没有它什么不做,返回零
7 undef值
在首次赋值前,变量的初始值就是特殊的undef(未定义)值,既不是数字也不是字符串。
其被当做数字时,作为0,当做字符时,当做空字符串。
8 defined函数
判断某个字符串是undef而不是空字符串,可以使用defined函数,如果是undef,该函数返回假,否则返回真
自己创建undef值
$madonna = undef;
9 列表和数组
列表指的是标量的有序集合,而数组则是存储列表的变量
$rocks[0] = 'Hello0';
$rocks[1] = 'Hello1';
$rocks[2] = 'Hello2';
$rocks[3] = 'Hello3';
$rocks[99] = 'Hello99';
数组最后一个元素的索引值是$#rocks
$end = $#rocks;
$number_of_rocks = $end + 1;
$rocks[$#rocks] = 'HelloLastValue'; #最后元素 或使用$rocks[-1]获取最后一个元素
列表直接量
(1, 2, 3)或(1, 2, 3,)或(1..3)或(1.7..3.7)
(5..1)空列表 只能向上计数
(1, 2, 5..9, 12)
(0..$#rocks) #可以是表达式
列表时,可以使用qw,省去输入引号的繁琐
("hello1", "hello2", "hello3", "hello4")
qw ( hello1 hello2 hello3 hello4 )
qw表示"quoted word"(加上单引号的单词)
除了用括号作为分隔符,Perl允许使用其他的定界符
qw ! hello1 hello2 hello3 hello4 !
qw / hello1 hello2 hello3 hello4 /
qw # hello1 hello2 hello3 hello4 #
列表赋值
($hello1, $hello2, $hello3, $hello4) = ("hello1", "hello2", "hello3", "hello4");
交换变量
($hello1, $hello2) = ($hello2, $hello1);
($hello[0], $hello[1]) = ($hello[1], $hello[0]);
($hello1, $hello2) = qw / hello1 hello2 /;
引用整个数组时,使用@符号
@rocks = qw / hello1 hello2 hello3 hello4 /;
@copy1 = @copy2; # 将数组中的列表复制到另一个数组
10 POP和PUSH操作符
pop操作符负责取出数组中最后一个元素并将其作为返回值返回:
@array = 5..9;
$hello1 = pop(@array); #$hello1变成了9 @array = (5, 6, 7, 8)
$hello2 = pop(@array);
如果数组是空的,pop什么也不做,直接返回undef.
push操作符负责向数组的尾端添加元素
push(@array, 0);
push @array, 8;
注:push和pop函数的第一个参数或唯一参数都必须是要操作的数组变量
11 shift和unshift操作符
此操作符是对数组的"开头"或最低下标值进行相应的处理
@arr = qw# dino fred barney #;
$m = shift(@arr); #$m变成"dino" @arr = qw# fred barney #;
$n = shift(@arr);
shift @arr; #@arr为空
$o = shift(@arr); #$o变成undef,@arr还是空
unshift(@arr, 5); #@arr = (5)
unshift(@arr, 4); #@arr = (4,5)
@others = 1..3;
unshift @arr, @others; #@arr = (1,2,3,4,5)
$i = 0;
while ($i<$#arr)
{
print $arr[$i];
print "\n";
$i= $i + 1;
}
输出:
1
2
3
4
12 splice操作符
push-pop和shift-unshift操作符都是针对数组首尾操作的
splice可以接收四个参数,第一个参数是要操作的目标数组,第二个参数是要操作的一组元素的开始位置
如果只有两个参数,则Perl会把从给定位置开始一直到末尾的全部元素取出来并返回。
实例:
@array = qw( hello1 hello2 hello3 hello4 hello5 );
@removed = splice @array, 2;
解释:
@removed = qw( hello3 hello4 hello5 );
@array = qw( hello1 hello2 );
通过第三个参数指定要操作的元素长度。
@array = qw( hello1 hello2 hello3 hello4 hello5 );
@removed = splice @array, 1, 2;
解释:
@removed = qw( hello2 hello3 );
@array = qw( hello1 hello4 hello5 );
第四个参数是要替换的列表
@array = qw( hello1 hello2 hello3 hello4 hello5 );
@removed = splice @array, 1, 2, qw( hello6); #在删除地方添加
解释:
@removed = qw( hello2 hello3 );
@array = qw( hello1 hello6 hello4 hello5 );
实际上,添加元素列表并不需要预先删除某些元素,把表示长度的第三个参数设为0,即可不加删除地插入新列表:
@array = qw( hello1 hello2 hello3 hello4 hello5 );
@removed = splice @array, 1, 0, qw( hello6);
解释:
@removed = qw( ); #没有删除任何元素
@array = qw( hello1 hello6 hello2 hello3 hello4 hello5 ); #Perl从索引位置1的地方插入新列表,然后顺移原来的元素
13 字符串中的数组内插
@array = qw( hello1 hello2 hello3 hello4 hello5 );
print "hello0 @array hellon\n";
#@array会在数组的各个元素之间自动添加分隔用的空格
print @array; #如果不加双引号,则元素会靠在一起,元素之间没有空格
@hello = qw( hello1 hello2 hello3 hello4 );
$hello = "hello";
print "this is $hello[3]\n";
print "this is ${hello}[3]\n";
print "this is $hello" . "[3]\n";
print "this is $hello\[3\]\n";
输出结果为:
this is hello4
this is hello[3]
this is hello[3]
this is hello[3]
14 foreach 控制结构
foreach $hello (qw/ hello1 hello2 hello3 /) #控制变量:$hello
{
print "One Hello is $hello.\n";
}
输出:
One Hello is hello1.
One Hello is hello2.
One Hello is hello3.
控制变量并不是列表元素的复制品,实际上,它是列表元素本身。
假如修改了控制变量的值,也就同时修改了这个列表的值
@hellos = qw/ hello1 hello2 hello3 /;
print "The hellos are:\n" ,@hellos, "\n";
foreach $hello (@hellos)
{
$hello = "\t$hello";
$hello .= "\n";
}
print "The hellos are:\n" ,@hellos;
输出:
The hellos are:
hello1hello2hello3
The hellos are:
hello1
hello2
hello3
当循环结束后,控制变量的值会变成什么,看下面的例子:
$hello = "GOODBOY";
@hellos = qw/ hello1 hello2 hello3 /;
foreach $hello (@hellos)
{
$hello = "\t$hello";
$hello .= "\n";
}
print "The hello value is still $hello\n";
结果:
The hello value is still GOODBOY
控制变量的值恢复到之前的值。
15 Perl的默认变量: $_
foreach (1..5)
{
print "I can count to $_!\n";
}
输出:
I can count to 1!
I can count to 2!
I can count to 3!
I can count to 4!
I can count to 5!
当未告知Perl使用哪个变量或数值时,Perl会自动使用$_
$_ = "hello\n";
print ;默认打印$_的值
16 reverse操作符
读取列表(或数组)的值,并按照相反的次序返回该列表。
@hello = 6..10;
@hello = reverse(@hello);
@hello = reverse 6..10;
reverse操作符不会修改传进来的参数。
17 sort操作符
读取列表(或数组)的值,并按照内部的字符编码顺序对它们进行排序。
@hellos = qw/ hello1 hello2 hello3 /;
@hellos = sort(@hellos);
或
@hellos = sort @hellos;
18 each操作符
从Perl 5.12版本开始,已经可以针对数组使用each操作符了。但是在此之前,each只能用于提取哈希的键-值。
每次对数组调用each,会返回数组中下一个元素所对应的两个值-该元素的索引以及该元素的值。
use 5.012;
my @hellos = qw/ hello1 hello2 hello3 hello4 /;
while ( my( $index, $value ) = each @hellos )
{
say "$index: $value";
}
如果不用each来实现,就得按照自己根据索引从小到大依次遍历,然后借助索引值获取元素的值
@hellos = qw/ hello1 hello2 hello3 hello4 /;
foreach $index (0..$#hellos)
{
print "$index: $hellos[$index]\n";
}
结果:
0: hello1
1: hello2
2: hello3
3: hello4
19 标量上下文和列表上下文
@people = qw( fred barney betty );
@sorted = sort @people; #列表上下文:fred, barney, betty
$number = 42 + @people; #标量上下文:42 + 3 得45
@list = @people; #得到三个元素的列表
$n = @people; #得到元素个数3
(1) 在标量上下文中使用产生列表的表达式
sort在标量上下文中总是返回undef;
reverse在列表上下文中自然地返回逆序后的列表
而在标量上下文中则返回逆序后的字符串
@backwards = reverse qw/ yabba dabba doo /; #得到doo,dabba,yabba
$backwards = reverse qw/ yabba dabba doo /; #得到oodabbadabbay
(2) 在列表上下文中使用产生标量的表达式
@hello = undef; #结果得到一个列表,而且仅有一个元素为未定义 undef是标量值,所以不会清空该数组
@hello =( ); # 这才是正确的清空数组的方法,和上面的做法完全不同
(3) 强制指定列表上下文
伪函数scalar
@rocks = qw( hello1 hello2 hello3 hello4 );
print "How many rocks do you have?\n";
print "I have ", @rocks, " rocks!\n"; #会输出列表的全部内容
print "I have ", scalar @rocks, " rocks!\n"; # 正确输出列表中元素的个数
输出:
How many rocks do you have?
I have hello1hello2hello3hello4 rocks!
I have 4 rocks!
注:不需要相应的函数用来强行切入到列表上下文,用不到这个需求
@hello = <STDIN>; #将输入的多行元素放到@hello数组中 退出输入后使用CTRL+D
chomp(@hello); #去掉每行末尾的回车符\n
比较好的写法是:
chomp(@hello = <STDIN>);
实例:
@hello = qw( fred betty barney dino wilma pebbles bamm-bamm );
chomp(@number = <STDIN>);
foreach (@number)
{
print "$hello[$_ - 1]\n";
}
测试:
[root@etl10 scott]# perl test.pl #输入1 6 5 7后按CTRL+D
1
6
5
7
fred
pebbles
wilma
bamm-bamm
20 子程序
sub定义子程序
sub marine
{
$n += 1;
print "Hello, sailor number $n!\n";
}
marine; #也可以写成&marine, 对marine子程序的调用
marine; #也可以写成&marine, 对marine子程序的调用
marine; #也可以写成&marine, 对marine子程序的调用
输出:
Hello, sailor number 1!
Hello, sailor number 2!
Hello, sailor number 3!
(1) 子程序的返回值
测试1:
$fred = 2;
$barney = 12;
sub marine
{
$fred + $barney;
}
$return_value = marine;
print "$return_value\n";
输出:
14
测试2:
$fred = 2;
$barney = 12;
sub marine
{
$fred + $barney;
print "Hello, sub marine\n"; #多添加了一句print打印输出
}
$return_value = marine;
print "$return_value\n";
输出:
1 #表示子程序正常执行,成功输出信息
(2) 传入参数
测试1:
#!/usr/bin/env perl
sub max
{
if ($_[0] > $_[1]) #$_[0]代码传入的第一个参数,$_[1]代表传入的第二个参数,以此类推
{
$_[0];
}
else
{
$_[1];
}
}
chomp($one = <STDIN>);
chomp($two = <STDIN>);
$return_max_value = max($one,$two);
print "$return_max_value\n";
测试结果:
[root@etl10 scott]# perl test.pl
12
34
34 #输出最大值
[root@etl10 scott]# perl test.pl
34
2
34 #输出最大值
[root@etl10 scott]# perl test.pl
2
2
2 #输出最大值
但是这不是最好的方法,里面$_[0],$_[1]......不太好
(3) 子程序中的私有变量
默认情况下,Perl里面的所有变量都是全局变量
但是可以利用my操作符来创建私有变量(词法变量 lexical variable)
sub max
{
my($m, $n); #定义私有变量
($m, $n) = @_; #将参数赋值给变量
if ($m > $n)
{
$m; #;是可以省略的 Perl允许省略语句块中最后一个分号,当且仅当代码块只有一行
}
else
{
$n; #;是可以省略的 Perl允许省略语句块中最后一个分号,当且仅当代码块只有一行
}
}
注:
my($m, $n); #定义私有变量
($m, $n) = @_; #将参数赋值给变量
这两行可以写成:
my($m, $n) = @_;
(4) 变长参数列表
对参数个数进行校验:
sub max
{
if (@_ != 2)
{
print "WARNING! $max should get exactly two arguments!\n";
}
my($m, $n);
($m, $n) = @_;
if ($m > $n)
{
$m
}
else
{
$n
}
}
接收任意参数的程序:
$maximum = &max(2,5,3,9,12);
sub max
{
my($max_so_far) = shift @_; # 数组中的第一个值,暂时设为最大值
foreach (@_) #遍历数组@_中的其他元素
{
if ($_ > $max_so_far)
{
$max_so_far = $_;
}
}
$max_so_far;
}
print "$maximum\n";
输出:
12
空参数列表:
@hello = ( ); # @hello为空的数组
$maximum = &max(@hello);
sub max
{
my($max_so_far) = shift @_; # 数组中的第一个值,为undef
foreach (@_) #遍历数组@_中的其他元素,因为数组为空的,所有循环不执行
{
if ($_ > $max_so_far)
{
$max_so_far = $_;
}
}
$max_so_far;
}
print "$maximum\n";
(5) 词法变量(my)
my操作符并不会更改变量赋值时的上下文:
my($num) = @_; #列表上下文,和 ($num) = @_;相同 $num被设置为第一个参数
my $num = @_; #标量上下文,和 $num = @_;相同$num被设置为参数的个数
测试:
print "$maximum\n";
@hellos = qw(hello faf afaf faf);
my($num) = @hellos;
print "$num\n";
my $num = @hellos;
print "$num\n";
输出:
hello
4
在my操作符不加括号时,只能用来声明单个词法变量:
my $hello1, $hello2; #错误,只声明了$hello1
my($hello1, $hello2);
在日常Perl编程中,最好新的变量都使用my声明,保持在自己的作用域中
foreach my $rock (qw/ hello1 hello2 hello3 /)
{
print "One rock is $rock.\n";
}
(6) use strict编译指令
use strict; #强制使用一些严格的,良好的编程风格
从Perl 5.12开始,如果使用编译指令指定最低Perl版本号的话,就相当于隐式打开了约束指令
use 5.012; #自动加载strict指令
(7) return操作符
#!/usr/bin/env perl
my @names = qw/ hello1 hello2 hello3 /;
my $result = &which_element_is("hello3", @names);
print "$result\n";
sub which_element_is
{
my($what, @array) = @_;
foreach (0..$#array)
{
if ($what eq $array[$_]) #字符相等比较符eq,数字相等比较符==
{
return $_;
}
}
-1;
}
结果为:
3 # hello3位于数组的第三个元素(序列为3)
(8) 省略与号
如果编译器在调用子程序前看到过子程序的定义,或者Perl通过语法规则判断它只能是子程序调用,
那么对待该子程序就可以像内置函数那样,在调用时省略与号。
my @cards = shuffle(@desk_of_cards); #shuffle上的&是多余的 将参数列表放进括号里面,就一定是函数
或者,如果Perl的内部编译器已经见过子程序的定义,通常也可以省略与号
sub division
{
$_[0] = $_[0];
}
my $quotient = division 355,113;
例外:假如这个子程序和Perl内置函数同名,就必须使用与号调用,避免歧义。
(9) 持久化私有变量
state来声明变量,该变量属于当前子程序的私有变量,并且在多次调用这个子程序期间保留该变量的值
测试1:
use 5.010; # 引入该特性
sub marine
{
state $n = 0;
$n += 1;
print "Hello, sailor number $n!\n";
}
输出:
Hello, sailor number 1!
Hello, sailor number 2!
测试2:
use 5.010; # 引入该特性
&marine;
&marine;
sub marine
{
$n = 0;
$n += 1;
print "Hello, sailor number $n!\n";
}
输出:
Hello, sailor number 1!
Hello, sailor number 1!
类似标量变量,其他任意类型的变量都可以被声明为state变量
#!/usr/bin/env perl
use 5.010;
running_sum(5,6);
running_sum(1..3);
running_sum(4);
sub running_sum
{
state $sum = 0;
state @numbers;
foreach my $number (@_) # 接收传入的值
{
push @numbers, $number;
$sum += $number;
}
say "The sum of (@numbers) is $sum.";
}
输出:
The sum of (5 6) is 11.
The sum of (5 6 1 2 3) is 17.
The sum of (5 6 1 2 3 4) is 21.
特别注意:
在使用数组和哈希类型的state变量时,还是有一些轻微的限制的。
在Perl 5.10中我们不能在列表上下文初始化这两种类型的state变量
state @array = qw/ a b c /;
#错误
Initialization of state variables in list context currently forbidden
到5.14还是无法使用
实例:
sub total
{
my $sum = 0;
foreach (@_)
{
$sum += $_;
}
return $sum;
}
my $result = total(1..100);
print "Result is :$result\n";
实例:
#!/usr/bin/env perl
use 5.010;
sub greet
{
state @people_lists;
state @people_before;
push @people_lists, @_;
if ($#people_lists == 0)
{
print "Hello ", @_, ", you are the first one!\n";
}
elsif ($#people_lists == 1)
{
print "Hello ", @_, ", you are the second one!\n";
}
else
{
print "Hello ", @_, ", There are [@people_before] before you!\n";
}
push @people_before, @_;
}
greet("CAT");
greet("DOG");
greet("PIG");
greet("APPLE");
greet("ORANGE");
输出:
Hello CAT, you are the first one! #第一位客户
Hello DOG, you are the second one! #第二位客户
Hello PIG, There are [CAT DOG] before you! #第三位,同时输出他前面还有几位
Hello APPLE, There are [CAT DOG PIG] before you!
Hello ORANGE, There are [CAT DOG PIG APPLE] before you!
实例2:
use 5.010;
greet('CAT');
greet('DOG');
greet('PIG');
greet('APPLE');
sub greet
{
state @names;
my $name = shift;
print "Hi $name! ";
if (@names)
{
print "I've seen: @names\n";
}
else
{
print "You are the first one here!\n";
}
push @names, $name;
}
输出:
Hi CAT! You are the first one here!
Hi DOG! I've seen: CAT
Hi PIG! I've seen: CAT DOG
Hi APPLE! I've seen: CAT DOG PIG