变量值
新手程序员往往只关注自己的程序要做些什么,而成熟的程序员则是在想如何为程序设计一个合适的数据模型。****变量帮你对数据进行抽象,变量的值就是让程序变得具体从而发挥实际作用。****变量的值可以是你期望的任何东西,比如名字、地址、家和学校的距离、你去年的花费。在程序中,对数据的格式要求往往非常严格。程序员需要有效的方法(简单,快速,高效)来表示他们的数据。
字符串
字符串就是一连串的字符(可以是文本也可以说是二进制数据)。比如它可以是你的名字,也可以是一个图片文件的内容,或者程序本身源代码。
在程序中,要表示一个字符串时,你需要将它们包围起来,最常见的就是使用单引号或双引号将它们包围起来:
my $name = 'Donner Odinson, Bringer of Despair';
my $address = "Room 539, Bilskirnir, Valhalla";
单引号包围的字符表示的意思就是****字面本身****,双引号包围的字符则****还可能具有非字面本身的意义(内插/转义)****。
单引号的使用有2个例外:要表示单引号自身时需要在前面加反斜杠;要表现反斜杠时也需要在前面加反斜杠:
'Don\'t forget to escape' #Don't forget to escape
'Modern \\ Perl' #Modern \ Perl
'backslash, not a quote: \\' #backslash, not a quote:\
双引号包围的字符则拥有更强的魔法,如支持更多反斜杠转义:
"\t"
"\n"
"\f"
"\b"
它们分别表示制表、换行、换页、退格。
当然对于双引号包围的普通字符意思不会变,仅仅表示这些是字符串字面本身。
如果要连接字符串,可以使用点号操作符(.):
my $kitten = 'Choco' . ' ' . 'Spidermonkey';
my $kitten = "Choco" . " " . "Spidermonkey";
你也可以在双引号中放入变量,那么变量的当前内容就会成为字符串的一部分,就好像把他们连接在一起:
my $factoid = "$name lives at $address!";
my $factoid = $name . ' lives at ' . $address . '!';
如果要表示双引号本身要在前面加反斜杠转义:
my $quote = "\"Ouch,\", he cried. \"That hurt!\""; #"Ouch,", he cried. "That hurt!"
上面这个例子反斜杠有点多,看起来乱糟糟的。所以Perl里还提供了操作符(q)和操作符(qq)来让这种情况变得简单。
q 操作符的效果就像单引号,不会内插;qq操作符类似双引号,会内插。
它们都需要定界符。定界符可以是2个相同的符号,也可以是成对的符号。
挑选合适的定界符可以避免上面例子中的反斜杠:
my $quote = qq{"Ouch", he said. "That hurt!"};
my $reminder = q^Don't escape the single quote!^;
my $complaint = q{It's too early to be awake.};
当你需要声明一个复杂的字符串时,可以是用heredoc语法:
my $blurb =<<'END_BLURB';
He looked up. "Change is the constant on which they all
can agree. We instead, born out of time, remain perfect
and perfectly self-aware. We only suffer change as we
pursue it. It is against our nature. We rebel against
that change. Shall we consider them greater for it?"
END_BLURB
这里<<'END_BLURB'
语法有3部分。二个小于号标志着这里是heredoc语法。用单引号引起表示这段字符串不做内插(类似单引号的行为,且无例外–单引号反斜杠都原样保留)。如果没有使用单引号引起默认就是双引号的行为(支持内插)。END_BLURB就是结束定界符。****注意结尾定界符必须要在那一行的行首!****
sub some_function {
my $ingredients =<<'END_INGREDIENTS';
Two eggs
One cup flour
Two ounces butter
One-quarter teaspoon salt
One cup milk
One drop vanilla
Season to taste
END_INGREDIENTS
}
Unicode和字符串
Unicode是一个用来表示世界上所有文字的字符系统。相对的就是纯英文字符,英文字符集只有127个字符,只需要8个比特位就够用了。这2种类型字符集都被广泛使用,Perl的字符串对2种类型都支持。
Unicode字符序列
每一个字符都有一个码点,这是该字符在Unicode字符集当中的唯一标识。
Octet序列(八位序列)
通常说的2进制数据就是8位序列,一个8比特位的数字,可以表示0到255。
为什么叫Octet序列而不是叫字节?不同的计算机对字节的定义不一样,而Octet则总是表示8个比特位。
****Perl默认将所有的输入数据都视为八位序列。****
字符编码
****文件句柄中使用Unicode编码****
如果你知道该以什么样的编码方式处理文件,那就可以在IO层进行指定,Perl会自动做相应的转换。如以UTF-8的编码方式读取文件:
open my $fh, '<:utf8', $textfile;
my $unicode_string = <$fh>;
对于已经打开了的文件句柄,则可以使用binmode方法:
binmode $fh, ':utf8';
my $unicode_string = <$fh>;
binmode STDOUT, ':utf8';
say $unicode_string;
想要方便的在所有地方都启用UTF-8,可以试试utf8::all模块。
****在数据中使用Unicode编码****
系统模块Encode提供了各种各样的编码转换功能。
my $from_utf8 = decode('utf8', $data); #对$data进行UTF-8解码
my $to_latin1 = encode('iso-8859-1', $string); #对$string进行拉丁解码
读取的数据时进行正确的解码,输出数据时进行正确的编码,能避免所有编码方面的问题。
****在源代码中使用Unicode编码****
启用utf8后就可以在代码中使用UTF-8字符了:
use utf8;
sub £_to_¥ { ... }
my $yen = £_to_¥('1000£');
这样写代码的前提条件是你的编辑器支持UTF-8,并且能将代码文件以正确的编码方式保存。
在双引号包围的字符串中,你可以使用\x{}语法来表示Unicode字符:
my $escaped_thorn = "\x{00FE}";
有些Unicode字符是有名字的,启用charnames后,可以使用\N{}语法用名字来表示:
use charnames ':full';
my $escaped_thorn = "\x{00FE}";
my $named_thorn = "\N{LATIN SMALL LETTER THORN}";
****隐式转换****
当你将多种字符集混合使用并且没有指明时,Perl会自动对字符串进行编码转换,这有可能导致出现非常隐秘的问题,所以不要这样做!
如果你的工作内容是处理Unicode,请使用Perl 5.16以上的版本,并且总是遵循这样一个原则:读取的数据时进行正确的解码,输出数据时进行正确的编码。
关于Perl与Unicode的更多细节请阅读:http://www.perl.com/pub/2012/04/perlunicook-standard-preamble.html
数字
Perl支持整型数字和浮点数字,你可以使用不同的方式来表示它们,二进制、八进制、十进制、十六进制:
my $integer = 42; #整型
my $float = 0.007; #浮点型
my $sci_float = 1.02e14; #科学计数法,浮点数
my $binary = 0b101010; #二进制0b前缀
my $octal = 052; #十六进制0前缀
my $hex = 0x20; #十六进制0x前缀
还可以使用下划线来增加可读性:(注意不是逗号,因为逗号在Perl中有特殊意义)
my $billion = 1000000000;
my $billion = 1_000_000_000;
my $billion = 10_0_00_00_0_0_0;
罕见的情况下你可能会有数字和字符相互转换的困扰,这时可以看看系统模块Scalar::Util( looks_like_number函数)。
如果你需要识别数字类型(如整型数字、浮点型数字),可以试试Regexp::Common模块(CPAN)。
Undef
Perl里的undef表示一个未分配、不确定、未知的值。
一个声明了但是没有定义的标量值就是undef:
my $name = undef; # unnecessary assignment
my $rank; # also contains undef
在布尔语境中,undef等效于假值。在字符串语境中内插undef值的变量将会产生一个警告:
my $undefined;
my $defined = $undefined . '... and so forth';
#Use of uninitialized value $undefined in concatenation (.) or string...
使用defined来测试undef值将返回假;测试undef外的其他任何值都返回真。
my $status = 'suffering from a cold';
say defined $status; # 1, which is a true value
say defined undef; # empty string; a false value
空列表
在赋值右边,使用一对小括号就表示一个空列表。
在标量语境中,空列表等价于undef;在列表语境中,就是一个空的列表。
当在赋值左边时,()强制为列表语境:
my $count = () = get_clown_hats();
首先空列表强制为列表语境,所以会在列表语境中调用get_clown_hats(),函数会返回一系列的值(列表)。然后赋值给空列表,空列表会将所有的值都丢弃,列表赋值这个操作又是在标量上下文,所以结果就会将返回元素的个数。现在看起来可能有点绕,但随着Perl技能的提高,你会越来越觉得自然。
列表
一个用逗号分隔的单个或多个表达式组就是一个列表。
可以作为值来使用:
my @first_fibs = (1, 1, 2, 3, 5, 8, 13, 21);
也可以用于被赋值:
my ($package, $filename, $line) = caller();
作为表达式列表:
say name(), ' => ', age();
****注意:列表不是由圆括号创建的,是由逗号创建的。****
使用范围操作符(..)可以很方便的创建列表:
my @chars = 'a' .. 'z';
my @count = 13 .. 27;
可以使用qw()操作符分隔空白来产生字符串列表:
my @stooges = qw( Larry Curly Moe Shemp Joey Kenny );
在qw()操作符中如果存在注释符号和逗号会产生警告,因为这种情况极有可能是你不小心写错了。
列表和数组相似,但他们不能互换。列表是值,而数组是容器。