▲标量数据和标量变量
标量数据和标量变量是两个完全不同的概念,标量数据表示数据的内容,也就是值;标量变量表示存储数据的容器。说到数据,我们指的是数据本身的内容,也就是值,它被写入内存后就是固定的,无法再改变。但是对于变量,正如其名,我们可以修改其中存储的数据。为了省事,都简单将其统称为标量。
▲标量分为数字和字符串两种情况,但对于Perl来说,它们是一样的东西,标量在内部是可以相应切换的。
数字
▲所有数字的内部格式都相同
Perl处理数字时用的是底层C库,且统一使用双精度浮点数来存储数据。定义整型数字和浮点数字,在Perl内部,都将它们统一转换为双精度浮点数来存储和计算。也就是说,Perl内部是没有整型数字的,程序中的整型常量本质上还是双精度数字。
▲整数直接量
直接量,就是在源代码中直接写成数据内容的形式。
整数直接量,比如:
02008-4061253564677889
注意:Perl允许在整数直接量中加入下划线,将若干位数分开,提高可读性,比如 61_253_564_677_889
▲非十进制整数的直接量
八进制:
直接量以数字0开头,后跟数字0到7
0377 #等于十进制的255
十六进制:
直接量以0x开头,后跟数字0到9以及字母A到F(或小写字母a到f)
0xff #或用大写FF,也等于十进制的255
二进制:
直接量以0b开头,后跟数字0或1
0b11111111 #等于十进制的255,当然也可以加下划线作为辅助视觉分隔符号
注意:前置0的写法只用于表示数字直接量,不能用于字符串和数字间的自动转换,后面会涉及到。
▲浮点数直接量
Perl的浮点数直接量写法接近于我们平时的书写习惯。
1.25255.000255.07.25e45 #7.25乘以10的45次方,e表示以10为幂-12e-24 #负12乘以10的-24次方-1.2E-23 #另一种写法,E换做大写
NOTE:
Perl5.22新增了十六进制浮点数直接量的写法。以0x开头,用p表示以2为幂。
0x1f.0p3
▲数字操作符
操作符相当于语言中的动词,操作符决定了处理名词的方式。
加减乘除:
2+3
5.1-2.4
3*12
10/3
取模运算:
10%3 #也就是10除以3的余数,结果是1
注意:取模操作符先取整,再求余数,所以10.5%3.2和10%3结果一样。
乘幂运算:
2**3 #表示2的3次方,结果是8
字符串
▲单引号内的字符串直接量
单引号内的字符串直接量就是写在一对单引号内的一串字符。前后两个单引号只是边界,并不是字符串的内容,用于让Perl判断字符串的开头与结尾。
'fred' #总共4个字符'barny' #总共6个字符'' #空字符串(没有字符)
注意:
1.反斜线转义
单引号圈引的字符串中,反斜线后面跟的只有反斜线或单引号时才表示转义。
'Don\'t' #Don't'D:\\Perl' #D:\Perl'hello\nthere' #hello\nthere,\n不会转成换行符,只是反斜线和字母n本身
2.两个引号之间输入的换行符就表示字符串中的换行符
'hellothere' #hello,换行符,there(总共11个字符)
▲双引号内的字符串直接量
双引号内的字符串直接量同样也是字符串序列,只不过这次换成双引号表示首尾。
双引号中的反斜线更为强大,可以转义许多控制字符,或是用八进制或十六进制写法来表示任何字符。
"barney" #和'barney'效果一样"hello world\n" #hello world,后面跟着换行符"coke\tsprite" #coke,制表符(tab)和sprite
Note:
1.双引号内的字符串直接量中,反斜线后面跟上不同字符,可以表示各种不同的意义(一般把这种借助反斜线组合表示特殊字符的方法称作反斜线转义)
清单如下:
2.双引号内字符串可以使用变量内插的写法。
▲字符串操作符
1.字符串拼接(.)
拼接运算得到一个更长的字符串,可以继续用于其它运算或保存到某个变量中。
连接运算必须显示使用串接操作符,而不像其他语言那样,把两个字符串前后写在一起就算拼接。
"hello".' '."world"."\n" #等同于"hello world\n"
2.字符串重复操作符(小写字母x)
"fred"x3 #得fredfredfred5x4.8 #得5555
注意:
1)左边操作数为要重复的字符串(如果是数字,会被转换成字符串),右边操作数为重复次数(某个数字),两者不可交换。
2)重复次数(右操作数)在使用前会先取整(4.8变成4),当重复次数小于1时,会生成长度为零的空字符串。
▲数字与字符串之间的自动转换
Perl会根据需要自动转换数字和字符串数据,转换的原则取决于操作符的意义。
对数字进行运算的操作符如果遇到字符串类型的操作数,Perl会自动将字符串转换成等效的十进制浮点数进行运算。字符串中非数字的部分(以及前置的空白字符)会被略过。完全不含数字的字符串会被转换成零。
"12"*"3" #得到36"12fred34"*"3" #也会得到36"fred"*"3" #得到0,并且不会出现警告信息,除非要求显示"Z".5*7 #得到Z35
注意:
自动转换总是基于十进制数字来处理的。
Perl的内置警告信息
当Perl发现程序代码中有可疑之处时,可以通过警告信息提示你。
▲启用警告机制的三种方法
1.通过编译指令(从Perl 5.6开始使用)
所谓编译指令,是指用于告诉Perl编译器该如何行动的指令
#!/usr/bin/perluse warnings;$yangdong = "fred"*"3";print "$yangdong";
2.命令行调用时给出-w选项
$ perl -w my_program
3.在shebang行启用警告选项
#!/usr/bin/perl -w
注意:
1)使用warnings编译指令的好处在于作用域仅限于书写该指令的文件内,-w的写法是打开了当前程序所引入的所有代码的警告机制。
2)启用警告机制只是让Perl提示一下可能有问题的地方,但Perl绝不会擅自改变代码的行为。
3)可以利用diagnostics编译指令,列出每个警告信息的简短描述和详尽解释。
use diagnostics;
但是,把use diagnostics加进程序后,程序会变慢,因为程序要预先加载警告和详细说明到内存,以便碰到需要时可以立即输出相关的错误信息。可以通过命令行选项-M实现优化,仅在需要时加载diagnostics编译指令。
$ perl -Mdiagnostics my_program
警告信息出现的(W numeric):W表示警告级别属于普通警告,numeric表示警告类型属于数字操作一类。
非十进制数字的转换
不是很明白
▲
可以用hex()或oct() 函数将字符串转换为对应的数字。
标量变量
▲
所谓变量,就是存储一个或多个值的容器,而标量变量,就是只保存一个值的变量。
变量的名字在整个程序中保持不变,但它的值可以在程序运行过程中不断修改变化。
变量名由字母或下划线开头,后跟多个字母、数字或下划线。
变量名是区分大小写的,$Fred和$fred是两个完全不同的变量。
▲标量的赋值
Perl的复制操作符就是等号,等号左边是变量名,右边是某个表达式。
$fred = 17;$barney = $fred + 3;$barney = $barney * 2; #$barney现在被设成$barney当前值乘以2后的结果,这种写法
太过常见,所以提供了更简便的写法:复合赋值操作
▲复合赋值操作符
1.几乎所有用来求值的双目操作符都有一个对应的加上等号的复合赋值操作符。
$fred = $fred + 5; #普通赋值操作符$fred += 5; #使用复合赋值操作符$barney = $barney * 3; #普通赋值操作符$barney *= 3; #使用复合赋值操作符
NOTE:
在内部实现上,复合赋值操作符就地更新原来的变量值,这样效率更高。传统的赋值操作符则需要先计算表达式,再把求值后的结果写入到变量。
2.用于连接字符串的复合赋值操作符(.=)
$str = $str . " "; #追加空格到$str末尾$str .= " "; #效果同上
3.乘幂复合赋值操作符
$fred **= 3;
用print输出结果
▲标量值作为参数
print "The answer is ";print 6*7;print ".\n";
▲交给print输出的也可以是一系列以逗号隔开的值
print "The answe is ",6*7,".\n";
实际上用逗号隔开一系列值的形式在Perl里被称作列表。后面会学习。
补充:
print "The answer is ",6*7,".\n";
写成完整形式:
print ("The answer is ",6*7,".\n");
这是一个有三个元素的列表,跟在print后面会依次并列输出三个值(不会有空格隔开),并且可以省掉括号。
如果把这个列表赋给一个数组变量,再用数组内插的形式打印,就会用空格隔开。
▲Perl 5.10增加了一个改良版print函数,称为say,它每次输出时都自动在末尾追加换行符。
use v5.10;say "The answe is ",6*7,".";
字符串中的标量变量内插
▲
我们一般用双引号圈引字符串,是因为双引号中可以实现变量内插,从而把变量替换为变量当前的内容。
$meal = "brontosaurus steak";$barnry = "fred ate a $meal"; #$barnry变成"fred ate a brontosaurus steak"$barnry = "fred ate a ".$meal; #效果相同的另一种写法(不用双引号一样可以得到相同的结果,但书写和阅读都很麻烦)
NOTE:
1.变量内插也被称为“双引号内插”,因为只有在双引号内部才可以这么做,在单引号中不行。
2.如果标量变量从未被赋值,内插时将使用空字符串替换。
$barnry = "fred ate a $meat"; #$barnry变成"fred ate a "
3.如果内插时单单就是变量本身,写不写双引号都行
print "$fred"; #多余的双引号print $fred; #合理写法
形式上,在单个变量两边加上双引号表示变量内插并没有错,但既然不是要构造更长的字符串,就没必要使用双引号的方式内插。
4.希望打印美元符号本身,用反斜线转义
print "The name is \$fred.\n"; #打印了美元符号
换种思路,既然不需要内插,就直接用单引号好了,避免混淆:
print 'The name is $fred'.".\n"; #打印了美元符号
5.变量内插时,Perl的原则是选用尽可能长且合法的变量名。
所以,如果在内插变量名后面需要紧跟其它合法的变量名字符(即字母、数字或下划线),Perl就无法判断,解决的办法就是隔离,可以在变量名两边加上花括号。
$whats会被认为whats是变量名而不是$what后面加个s
6.如果在变量名后紧跟的字符是左方括号或左花括号,请使用反斜线转义。如果跟的是撇号或者连着的两个冒号,也请使用反斜线转义,或者直接使用花括号隔离。不转义的写法有另外的意义。
用代码点创建字符
1.已知代码点,通过chr()函数转换成字符
2.已知字符,取得其代码点,可以通过ord()函数
操作符的优先级与结合性
1.在加减乘除中,Perl的计算优先级和数学计算是一样的,可以用圆括号改变执行的优先级。
2.字符串连接或乘幂等其它操作符,参考perlop文档:cmd窗口执行perl perlop
比较操作符
1.比较数字大小
<、<=、==、>=、>、!=
2.比较字符串
lt、le、eq、ge、gt、ne
if控制结构
▲
学会如何比较两个值后,可以根据比较结果决定下一步流程,Perl有if条件语句,只要条件为真,就执行语句块中的内容。
$name = 'yfb';if($name gt 'fred'){ print "'$name' comes after 'fred' in sorted order.\n";}
▲
需要在条件不成立时才执行的内容放在else关键字对应的语句块中。
$name = 'barney';if($name gt 'fred'){ print "'$name' comes after 'fred' in sorted order.\n";}else{ print "'$name' does not come after 'fred'.\n"; print "Maybe it's the same string, in fact.\n";}
注意:
条件语句中的语句块周围一定要加上表示边界的花括号。
布尔值
▲
任何标量值都可以成为if控制结构里的判断条件。
▲
如果把表达式返回的真假值保存到变量中,那么在判断时可以直接检查该变量的值,可读性更强。
$is_bigger = $name gt 'fred';
if($is_bigger){...}
▲
Perl没有专用的布尔数据类型,它是靠一些简单的规则来判断的:
1.如果是数字,0为假,所有其它数字都为真。
if(0){print "OK\n";}
2.如果是字符串,空字符串('')以及字符串'0'都为假,所有其它字符串都为真。
if(''){print "OK\n";}
3.如果变量还未被赋值,那么返回假。
if($yfb){print "OK\n";}
4.如果要取得相反的布尔值,可以用!这个单目取反操作符。
if(!$is_bigger){ #如果$is_bigger不为真,则执行这里的代码}
NOTE:
由于!会颠倒真假值,并且Perl又没有专门的布尔类型的变量,所以!总会返回某个代表真假的标量值。而数字1和0都是非常自然的表示真假的标量值,所以人们常常喜欢把布尔值归一化到这两个值来表示。转换过程只是利用了连续两次的!反转操作,得到表示布尔值的变量。
$still_true = 'Fred';print "$still_true\n"; #$still_true的值为标量值'Fred'(当然这个值是表示真的)$still_true = !!'Fred';print "$still_true\n"; #$still_true被转换成了表示“真”的标量值1 $still_false = '0';print "$still_false\n"; #$still_false的值为标量值'0'(表示假)$still_false = !!'0';print "$still_false\n"; #$still_false被转换成了表示“假”的标量值0(书上说可能是0,但实际测试显示是空,用的Perl版本是v5.32.0)
获取用户输入
让Perl读取从键盘输入的值,使用“行输入”操作符
$line = ;if($line eq "\n"){ print "That was just a blank line!\n";}else{ print "That line of input was: $line"; }
注意:
从读取的字符串是包含末尾的换行符的。
实际应用时,往往不需要末尾的那个换行符,需要用chomp()操作符去掉。
chomp操作符
▲作用:
去掉字符串末尾的换行符,如果没有,就啥都不干。
$text = "a line of text\n";chomp($text);
▲Perl可以将任何一个使用变量的地方都写成赋值的形式
chomp($text = );print $text;
▲chomp()本质上是函数
作为一个函数,他有自己的返回值。chomp()返回的是实际移除的字符数,但这个数字几乎没用。
$text = ;$betty = chomp $text; #会得到返回值1
NOTE:
对于函数而言,这种括号基本都是可加可不加的,这是Perl的一项惯例:除非去掉括号会改变表达式的意义,否则括号可以省略。
▲如果字符串后面有两个以上的换行符,chomp()只去掉最后那个并返回1;如果末尾没有换行符,就啥也不干并返回零。基本上,我们不用关心chomp()的返回值。
while控制结构
在while循环中,只要条件持续为真,就不断执行块里的程序代码:
$count = 0;while($count < 10){ $count += 2; print "count is now $count\n"; #依次打印2、4、6、8、10 }
这里的真假值与if条件语句里的真假值定义相同,代码块外围的花括号也和if控制结构一样必不可少。
条件表达式在第一次执行代码块之前就会被求值,如果它一开始就为假,里面的循环就会被直接略过。
undef值
▲
如果还没赋值就用到标量变量,系统不会报错,也不会终止程序。
在首次赋值前,变量的初始值就是特殊的undef值。
▲
1.如果把未赋值的标量变量当成数字用,它就会表现得像零;
#累加一些奇数$n = 1;while($n < 10){ $sum += $n; $n += 2; #准备好下一个奇数}print "The total was $sum.\n";
2.如果把未赋值的标量变量当成字符串用,它就会表现得像空字符串。
$string .= "more text\n";
3.但undef本身既不是数字也不是空字符串,它是一种独立类型的标量值。
▲
如果开启警告信息,Perl会对未定义值的不寻常使用发出警告。
defined函数
▲
要判断某个字符串是否为undef,可以用defined函数。如果是undef,该函数就返回假;否则,即便是空字符串,那也是已定义的值,函数返回真。
$next_line = ;if(defined($next_line)){ print "The input was $next_line";}else{ print "No input available!\n";}
▲
自己创建undef值,可以使用同名的undef操作符:
$next_line = undef; #回到虚无,仿佛从未用过。