Perl 入门

1. Perl 也允许使用非10 为底的数字。八进制以0 开头,十六进制以0x 开头,二进制0b 开头.在十
六进制中A 到F(或者a 到f)分别表示10 到15:
0377 #八进制数字377,等同于十进制数字255
0xff #十六进制数字FF,等同于十进制数字255
0b11111111 #等同于十进制数字255

2. Perl 除了提供通常的操作符加(+),减(-),乘(*),除(/)等等之外:
2+3 #2+3,5
5.1-2.4 #5.1-2.4,2.7
3*12 #3*12,36
14/2 #14/2,7
10.2/0.3 #10.2/0.3,34
10/3 #通常是浮点除,3.33333… …
还提供了模数运算符(%)。10%3 的值是10 除以3 的余数
如2**3,表示2 的3 次方,等于

3. 字符串是一串字符(如hello)。字符串可能是字符的任意组合◆。最短的字符串不含任何字符。最长的字符串,可以填满整个内存.
◆和C,C++不同,Perl 中NUL 字符没有特殊的含义。Perl 能计算长度,不用靠null 来判断字符串是否结束。
和数字一样,字符串也可由文字符号(literal)来表示,它用来在Perl 程序中代表某个字符串。有两种类型的字符串:单引号字符串和双引号字符串。

除了单引号,或者反斜线(包括换行字符,如果字符串在下一行继续)之外的任何字符都表示它自身
‘fred’ #四个字符:f,r,e,d
‘barney’#六个字符
‘’ #空字符(没有字符)
‘Don’t let an apostrophe end this string prematruely!’
‘the last character of this string is a backslash: \\’
‘hello\n’#hello 紧跟着反斜线和n
‘hello
there’ #hello,换行,there (共11 个字符)
‘\’\\’ #单引号(’)跟着反斜线(\)

双引号字符串和在其它语言类似。它也是字符的序列,不同点在于,其由双引号括起来的。现在,反斜线可以用来表示控制字符,或者八进制,十六进制数的表示。下面是一些双引号字符串的例子:
“barney”#等同于‘barney’
“hello world\n”#hello world,换行
“the last character of this string is a quote mark:\””
“coke\tsprite”# coke, a tab(一个制表符), sprite

“hello”. “world” # 同于“helloworld”
“hello”. ‘’. “world”#同于“hello world”
‘hello world’. “\n” #同于“hello world\n”

“fred”x 3 # “fredfredfred”
“barney”x (4+1) # “barney”x 5, “barneybarneybarneybarneybarney”
5 x 4 #实际上是“5”x 4, “5555”

4. 数字和字符串之间的自动转换
当在需要数字的地方使用了字符串(如,乘法),Perl 将自动把字符串转换为其等价的数字,就像输入的是十进制浮点数一
样◆。因此“12”* “3”将给出36。后面的非数字部分和前面的空格将被去掉,如“12fred34”* “3”将给出36 而不会用任何
提示◆。在极端情形,当一个不含任何数字的字符串将别转换为0。如,将“fred”当作数字来使用时。


5. 标量变量可以存放一个标量值。
标量变量的名字由一个美圆符号($)后接Perl 标识符:由字母或下划线开头,后接字母,数字,或者下划线。或者说由字母,数字和下划线组成,但不能由数字开头。大小写是严格区分的:变量$Fred 和变量$fred
是不同的。任意字母,数字,下划线都有意义,如:
$a_very_long_variable_that_ends_in_1

标量赋值
$fred = 17; #将17 赋给变量$fred
$barney =‘hello’; #将五个字母的字符串‘hello’赋给$barney
$barney = $fred + 3;# 将$fred 的值加上三赋给$barney (20)
$barney= $barney*2;#将变量$barney 乘2 再赋给$barney (40)

$barney = $barney*3;    $barney*=3;
$str = str . “”; #$str 后接空格
$str .= “”’; #同上


6. 字符串中标量变量的内插
$mean = “brontosaurus steak”;
$barney = “fred ate a $meal”; #$barney 现在是“fred ate a brontosaurus steak”
$barney = ‘fred ate a’. $meal; #同上

如果一个变量未被赋值,则将使用空值替换
print “$fred”; #引号是没有必要的
print $fred; #更好的写法

在字符串中变量前($符号前)加上反斜线(\),变量将不会被内插(替换):
$fred = ‘hello’;
print “The name is \$fred .\n”; #打印出美圆符号,变量不会被其值替换
print ‘The name is $fred’. “\n”; #同上
print "Try to get value of \$fred: $fred\n";

变量名将是字符串中有意义的最长的那一个。这可能在当你需要在某次匹配就替换的情况下出问题。Perl 提供了一种类似于shell 的分隔符:花括号({})。用花括号将变量名括起来。或者将字符串分隔成几个部分,再用连接符( . )串起来:
$fred = "Kelvin";
$freds = "Damon";
print "Try to get value of \n\$fred: ${fred}s\n\$freds: $freds\n${freds}\n";

7. 比较运算符
35 != 30+5 #false
35 == 35.0 #true
‘35’eq‘35.0’ #false (按照字符串比较)
‘fred’lt ‘barney’ #false
‘fred’lt ‘free’ #true
‘fred’eq ‘fred’ #true
‘fred’eq ‘Fred’ #false
‘’gt ‘’ #true

8. 控制结构
if
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”;
}

while
$count = 0;
while ($count < 10) {
$count + = 2;
print “count is now $count\n”; #打印出2 4 6 8 10
}

foreach
@rocks = qw/ bedrock slate lava /;
foreach $rocks(@rocks){
$rock = “\t$rock”; #@rocks 的每一个元素前加入一个tab
$rock . = “\n”; #每一个元素后加一个换行符
}
print “The rocks are:\n”,@rocks; #每一个元素都被缩进了,并且一个元素占一行

类似Boolean类型
$is_bigger = $name gt‘fred’;
if($is_bigger){… }
判断依据
● 如果值为数字,0 是false;其余为真
● 如果值为字符串,则空串(‘’)为false;其余为真
● 如果值的类型既不是数字又不是字符串,则将其转换为数字或字符串后再利用上述规则◆。
这意味着undef(很快会看到)为false。所有的引用(在Alpaca 书中有详细讨论)都是true。
字符串‘0’是唯一一个非空但值为0 的串。

9. 用户输入
$line = <STDIN>;
if($line eq “\n”){
print “That was just a blank line!\n”;
}else{
print “That line of input was: $line”;
}



完全正确,只是有未初始化的警告:
#n = 1;
while($n < 3){
$sum += $n;
$n +=1;
}
print "The total was $sum.\n";

10. 常用函数
define:检查是否初始化
$madonna = <STDIN>;
If ($defined ($madonna)){
print “The input was $madonna”;
}else{
print “No input available!\n”;
}

qw:
实践表明,字符串的列表(如上例)在Perl 中经常使用。有一种简便的方法可以不用输入大量的引号而达到类似的功能,那就是使用qw。qw 表示“quoted words”或者“quoted by whitespace”
(“fred”, “barney”, “betty”, “wilma”, “dino”)
qw(fred barney betty wilma dino ) #同上,但输入更少

chomp:去掉最后的\n
$line = "ab\\nc\n";
print $line;
chomp($line);
print $line;
chomp (@lines = <STDIN>); #读入所有的行,不包括换行符

reverse
reverse(逆转)操作将输入的一串列表(可能是数组)按相反的顺序返回。如果不喜欢范围操作符: .,只能从小到大, 那可以使用 reverse 来解决这个问题:
@fred = 6 .
.10;
@barney = reverse (@fred);
@wilma = reverse 6 .
.10;
@fred = reverse @fred;
#得到 10,9,8,7,6
#同上,没有使用额外的数组

sort:需要将结果存回原数据结构
sort 操作将输入的一串列表(可能是数组)根据内部的字符顺序进行排序。如对于 ASCII 字符串,将根据 ASCII 序进行排 序。当然,ASCII 中有一些奇怪的地方,如大写字母在小写字符的前面,数字在字符的前面,而标点符号散布在各处。但按 ASCII 排序只是其默认的行为,在第十三章中,可以看到如何按你想要的顺序进行排序的方法:
@rocks = qw/ bedrock slate rubble granite /; #得到 bedrock, granite, rubble, slate
@sorted = sort(@rocks);
@back = reverse sort @rocks; #为 slate 到 bedrock
@rocks = sort @rocks;
@numbers = sort 97 .
.102;
#将排序的值写回@rocks
#得到 100,101,102,97,98,99

scalar:告诉 Perl 提供一个标量 context
偶尔,你可能需要标量 context 而 Perl 期望的是列表。这种情况下,可以使用函数 scalar。它不是一个真实的函数因为其仅 是告诉 Perl 提供一个标量 context:
@rocks = qw(talc quartz jade obsidian);
print “
How many rocks do you have?\n”
;
print “ have ” @rocks, “
I
,
rocks!\n”
;
print “ have ” scalar @rocks, “
I
,
rocks!\n”
;
#错误,输出 rocks 的名字
#正确,输出其数字

reverse: hash 的反转,键值调换,如有重复键,最后一次的值保留:
%inverse_hash = reverse %any_hash;


keys 函数会返回此 hash 的所有 keys,values 函数将返回所有的 values。如果 hash 中没有元素,则此函数将返回空列表:
my %hash = (“
a”=>1, “
b”=>2, “
c”=>3);
my @k = keys %hash;
my @v = values %hash;


11. 数组和列表
$arr[0] = "2";
$arr[5] = "4";
print $arr[0]*$arr[$#arr]."\n";  #8
print $arr[0]*$arr[$#arr+1]."\n"; #0
print $arr[0]*$arr[-1]."\n";  #8. if use -2, it represents nodes before the last one

@rocks = qw(aa bb cc dd);
$num = $#rocks;
print "$rocks[$num]\n";

数组是由括号括起来并且其元素由逗号分隔开的列表。这些值组成了数组的元素:
(1 ..5) #同(1,2,3,4,5)
(1.7..5.7) #同上— 最小值和最大值被转换成整数
(5 ..1) #空列表— ..中的左值应小于右值,否则为空
(0,2 .. 6,10,12)#同(0,2,3,4,5,6,10,12)
($m ..$n) #由$m 和$n 的值决定
(0 .. $#rocks) #上节中有$#rocks 的介绍

列表赋值
($fred, $barney, $dino) = (“flintstone”, “rubble”, undef);
($fred, $barney) = ($barney, $fred) #交换两个变量
($betty[0],$betty[1]) = ($betty[1],$betty[0]);

($fred, $barney) = qw <flintstone rubble slate granite>; #两个值被忽略了
($wilma,$dino) = qw[flintstone]; #$dino 为undef

@rocks = qw / bedrock slate lava /;
@tiny = (); #空表
@giant = 1..1e5; #包含100,000 个元素的表
@stuff = (@giant, undef, @giant); #包含200,001 个元素的表
@dino = “granite”;
@quarry = (@rocks, “crushed rock”, @tiny, $dino);
@copy = @quarry; #将一个数组中的值拷贝的另一个数组中

pop
@array = 5..9;
$fred = pop(@array); #$fred 得到9,@array 现在为(5,6,7,8)
$barney = pop @array; #$barney gets 8, @array 现在为(5,6,7)
pop @array; #@array 现在为(5,6)(7 被丢弃了)
如果数组为空,那pop 什么也不做(因为没有元素可以移出),并返回undef。

push
push(@array,0); #@array 现在为(5,6,0)
push @array,8; #@array 现在为(5,6,0,8)
push @array,1..10; #@array 现在多了10 个元素
@others =qw/9 0 2 1 0 /;
push @array,@others; #@array 现在又多了5 个元素(共有19 个)

shift && unshift
push 和pop 对数组的末尾进行操作(或者说数组右边有最大下标的元素,这依赖于你是怎样思考的)。相应的,unshift 和shift 对一个数组的开头进行操作(数组的左端有最小下标的元素)。下面是一些例子:
@array = qw# dino fred barney #;
$m = shift (@array); #$m 得到“dino”, @array 现在为(“fred”, “barney”)
$n = shift @array; #$n 得到”fred”, @array 现在为(“barney”)
shift @array; #@array 现在为空
$o = shift @array; #$o 得到undef, @arry 仍为空
unshift(@array,5); #@array 现在为(5)
unshift @array,4; #@array 现在为(4,5)
@others = 1..3;
unshift @array, @others; #array 现在为(1,2,3,4,5)

12. 默认变量
$_ = "default variable\n";
print;

foreach (1..10)
{
    print "I can count to default value $_\n";
}

13. context
@people = qw (dd cc bb aa);
print "people:\n@people\n";
@sorted = sort(@people);
print "sorted:\n@sorted\n";
$number = @sorted;
print $number."\n";

另一个例子是 reverse。在列表 context 中,它返回反转的列表。在标量 context 中,返回反转的字符串(或者将反转的结果串成一个字符串):
@backwards = reverse qw / yabba dabba doo /;
#返回 doo, dabba, yabba
$backwards = reverse qw/ yabba
dabba doo /;
#返回 oodabbadabbay

让我们看看已经出现过的一些别的表达式及其 context。下面是一些标量 context:
$fred = something;
$fred[3] = something;
123 + something;
something + 654
if(something){ ... }
$fred[something] = something;
下面是一些列表 context:
@fred = something;
($fred, $barney) = something;
($fred) = something;
push @fred, something;
foreach $fred(something)
sort something
reverse something
print something


@bamey = "this is ".' '."world";
foreach $s(@bamey)
{
    print $s."\n";
}  #结果为: this is world

@arr = qw [bb cc aa ee];
print "I have ".@arr." arr\n"; #answer is: I have 4 arr
print "I have ",@arr," arr\n"; #answer is:I have bbccaaee arr
print "I have ", scalar @arr," arr\n";  #answer is: I have 4 arr


14. hash的定义使用
定义
my %some_hash = ("last_name", "kelvin", "first_name", "liu");
取值
$hash{$some_key}
赋值
$family_name{“ fred”} = flintstone;

#my %some_hash = ("last_name", "kelvin", "first_name", "liu");
my %some_hash = (
"last_name" => "kelvin",
"first_name" => "liu"
);
my @keys = keys %some_hash;
my @values = values %some_hash;
my @array = %some_hash;
print @array."\n"; #4
print "@array"."\n";  #first_name liu last_name kelvin
my $key;
my $value;
foreach $key(@keys)
{
    print $key."\n";
}
=cut

 
my %some_hash = (
"last_name" => "kelvin",
"first_name" => "liu"
);
my @keys = keys %some_hash;
my @values = keys %some_hash;
while ((my $key,my $value) = each %some_hash)
{
    print $key." and ".$value."\n";
}
foreach my $key2 (sort keys %some_hash)
{
    print "key = ".$key2.", value = ".$some_hash{$key2}."\n";
}
if (exists $some_hash{"first_name"})
{
    delete $some_hash{"last_name"};
    my @keys3 = keys %some_hash;
    foreach my $key4 (@keys3)
    {
        print "compare with $key4"."\n";
        if ($key4 eq "last_name")
        {
            print "this is $key4"."\n";
            exit;
        }
        print "$key4 not equals last_name\n";
    }
}

15. regular expression:正则表达式
点(.)是通配符, 它可以匹配任何单个的字符, 但不包括换行符(“\n”).
如果只希望点(.)匹配句号,可以使用反斜线。这条规则对 Perl 正则表达式中所有元字符均有效:
元字符前使用反斜线将使它变成普通的字符。如,模式/3\.14159/中的点(.)即不是通配符。

可以这样看待星号(*): “前面的东西,重复任意次数,包括 0 次.只是前面 的一个字符,不是任意匹配。
将.*叫做“任意字符串匹配模式”,因为任意的字符串均能被匹配上

因为加(+)意指一个或多个,因此至少是一个。可以这样看待加(+): “最后一项, (可选的)至少还 有一项。 ”

问号(?),其含义是前面一个项出现一次,或者不出现。也就是说,前面这个项出现 1 次或者 0 次,此外不会有其它情况。因此,/barm-?bamm/只匹配:bamm-bamm 或 bammbamm。这很容易记住: “前面 的这个项,出现?或者不出现?”

模式/(fred)+/能匹配上像 fredfredfred 这样的字符串, 这更可能是你所希望的。 那么模式/(fred)*/ 呢?它将匹配上像 hello,world 这样的字符串◆。

任何数字的类,[0-9],可以被简写为:\d。
if(/HAL-[0-9]+/){
print “ string mentions some model of HAL computer.\n”
The
;
}
例子可以被写作/HAL-\d+/。
\w 被称作 “ word’ 字符:[A-Za-z0-9_]。
\w 不能匹配单词,而只能匹配单个字符。为了匹配整个单词,需要后接加号。模式 /fred \w+ barney/将匹配 fred,空 格,一个“单词(word) ,然后是空格和 barney。因此,如果 fred 和 barney 之间有一个单词◆,由单个空格分隔开,它将 ” 能匹配上。

\s 对于匹配空白(whitespace)将非常方便。它等价 于[\f\t\n\r ],其含 5 个空白字符:格式符(form-feed) ;制表符(tab),换行符,回车,以及空格符。

希望得到这三种简写形式的补集。如果那样的话,你可以使用[^\d], [^\w], 和[^\s],其含义分别是,非数
字的字符,非 word(记住我们对 word 的定义)的字符,和非空白的字符。也可以使用它们对应的大写形式:\D, \W, \S 来 完成。它们将匹配它们对应的小写形式不能匹配上的字符。

/i
要创建一个大小写无关的模式,如匹配 FRED 时,也能匹配上 fred, Fred,可以使用修饰符 /i:
if(/yes/i) {#大小写无关
print “ that case, I recommend that you go bowling.\n” ;
}

/s
可以使用/s 这个修饰符。它将模式中点(.)◆的行为变成同字符类[\d\D]的行为类似:可以匹配任何字符,包括换 行符。
$_ = “ saw Barney\ndown at the bowing alley\nwith Fred\nlast night.\n” ;
if(/Barney.*Fred/s){
print “ That string mentions Fred after Barney!\n” ;
}
如果不使用/s,那么上述模式将不能被匹配上,因为这两个字符不在同一行中。

/x
/x 修饰符,允许你在模式中加入任何数量的空白,以方便阅读:
/-?\d+\.?\d*/ #这是什么含义?
/ -? \d+ \.? \d* /x #要好些
由于/x 允许模式中使用空白,那么模式中的空格,制表符将被忽略。可以在空格前加上反斜线或者使用\t(许多方法中的一 种) ,但匹配空白更常用的方法是使用\s(\s*或\s+)。
Perl 中,注释可以被作为空白,因此使用/x,可以在模式中加上注释:
/
-?
#可选的负号
\d+ #小数点前一个或多个十进制数字
\.? #可选的小数点
\d* #小数点后一些可选的十进制数字
/x
#模式结束

^ and $:开始结尾匹配
符号^(脱字字符◆)表示在字符串的开头进行匹配,而符号$则表示在结尾◆。因此,模式/^fred/只匹配字符串的开头部分; 它不会匹配上 manfred man。而/rock$/只在结尾处匹配;其不会匹配上 knute rockne。

一个经常使用的例子是/^\s*$/,它将匹配一个空行(blank line) 。这 里的“ blank(空白)” ,可以是空白符,如制表符,空格等,它们是不可见的。

锚定不仅仅针对字符串的两头。词界锚定,\b,是针对单词使用的。如/\bfred\b/可以匹配上单词 fred,但不能匹配 frederick, alfred, man fred mann。这同字处理软件中的 “ 全字匹配(match whole words only)”
是类似的。

非词界锚定为\B。它将在任何非\b 匹配的点上进行匹配。因此,模式/\bsearch\B/将匹配 searches,searching, searched, 但不能 匹配 search,或者 researching。

对$_进行匹配只是默认的行为,使用绑定操作符(=~)将告诉 Perl 将右边的模式在左边的字符串上进行匹配,而非对$_匹配。 例如:
my $some_other = “dream of betty rubble.”;
if($some_other =~ /\brub/){
print “ Aye, there’ the rub.\n” ;
}

匹配上的那部分字符串将自动存储在$&之中。
$`中含有正则表达式引擎在匹配成功前所找到的变 量,而$'为此模式还没有匹配的剩余部分。如果将这三个变量放在一起,你将得到原始字符串:

模式/a{5,15}/将匹配 5 个到 15 个 a 中的任意一个(包括 5,和 15) 。如果 a 出现了 3 次,则次数太少,而不能匹配上;
如果省略掉第二个数字(逗号留下) ,现在没有上限了。
如果除了上限数字外,逗号也被省略了,那将匹配确定的次数.
星号(*)等同于{0,},表示 0 个或多个。加号(+)等同于{1,},表示 1 个或多个。而问 号(?)则等同于{0,1}。


16. 循环控制语句
Last:
last 会立刻结束循环。(这同C 语言或其它语言中的“break”语句类似)。它从循环块中“紧急退出”。当执行到last,循环即结束,如下例:
#输出所有出现fred 的行,直到遇见_ _END_ _标记
while(<STDIN>){
if(/_ _ END_ _/){
#这个标记之后不会有其它输入了
last;
}elsif(/fred/){
print;
}
}
##last 跳转到这里##

next:
有时还不希望结束循环,但本次循环已经结束。这种情况下,next 是非常适用的。它跳到当前循环块的最后面(块内)◆。
next 之后,又会进入下一轮循环(这和C 或者类似语言的“continue”相似):
#分析输入文件的单词
while(<>){
foreach(split){ #将$_分拆成单词,并依次赋给$_
$total++;
next if/\W/; #不是“words”的被跳过
$valid++;
$count{$_}++; #对每个单词进行计数
##next 跳到这里##
}
}
print “total things = $total, valid words = $valid\n”;
foreach $word (sort keys %count){
print “$word was seen $count{$word} time.\n”;
}

redo:
循环控制的第三个操作是redo。它会调到当前循环块的顶端,不进行条件表达式判断以及接着本次循环。(在C 或类似语言中没有这种操作。)下面是一个例子:
#输入测试
my @words = qw{ fred barney pebbles dinoWilma betty };
my $errors = 0;
foreach(@words){
##redo 跳到这里##
print “Type the word ‘$_’: ”;
chomp(my $try = <STDIN>);
if($try ne $_){
print “sorry –That’s not right.\n\n”;
$errors++;
redo; #跳转到循环顶端
}
}
print “You’ve completed the test, with $errors errors.\n”

三元操作符:?
my $size =
($width < 10 ) ? “small”:
($width < 20) ? “medium”:
($width < 50) ? “large”:
“extra_large”; #default

发布了32 篇原创文章 · 获赞 4 · 访问量 4万+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章