第八章 正则表示式
1)
=~: 匹配为真,没有匹配为假
=!: 不匹配为真,匹配为假。
对数组匹配 grep (/abc/,@a);
split(/abc/,$line)根据模式匹配分割字符串
模式匹配的3中类型:
m//模式匹配, s///匹配并替换, tr///逐一替换,翻译
2)字符匹配
+ 一个或多个相同的前导字符
* 0个、1个或多个相同字符
? 0个或1个
. 匹配除换行外地所有单个字符
{} 匹配指定数目的字符
3)模式匹配:选择
[] 匹配一组字符中的任一个
[^] 表示除其之外的所有字符
/^-?\d+$/: 匹配十进制数字
/^-?0[xX][\da-fa-F]+$/ : 匹配十六进制数字
4) 转义符和定界符
\: 转义符
\d 任意数字[0-9] \D 除了数字以外的任意字符
\w 任意单词字符[_0-9a-zA-Z] \W 任意非单词字符[^_0-9a-zA-Z]
\s 空白 [\r\t\n\f] \S非空白[^\r\t\n\f]
定界符:
^或\A 仅匹配字符串首 $或\Z 仅匹配字符串尾
\b 匹配单词边界 \b 单词内部匹配
5)模式的重用
\n 来多次引用 : 把匹配的值存起来以后使用。
/\d{2}([\W])\d{2}\1\d{2}/ 匹配12-05-92 但不匹配 12-05.92
6)模式变量
在模式匹配后调用重用部分的结果可用变量$n,全部的结果,匹配模式用变量$&,包含不在括号中的。匹配
处之前的部分用变量$`,匹配处之后的部分变量用$'。也可用列表一次取得。
$string = "This string contains the number 25.11.";
$string =~ /-?(\d+)\?(\d+)/; #匹配结果为25.11
$integerpart = $1; #now $integerpart=25
$decimalpart = $2; # now $decimalpart = 11
$totalpart = $&; #now totalpart=25.11
@result =~ /-?(\d+)\.?(\d+)/;
7)匹配选项
g 匹配所有可能的模式
匹配的循环:每次匹配记住上次的位置
while("balata" =~ /.a/g) {
$match = $&;
print ("$match\n");
}
结果
ba
la
ta
当要匹配的字符串改变时重新开始搜索
当使用了选项g时,可用函数pos来控制下次匹配的偏移
$offset = pos($string); 下一个匹配开始的位置;
pos($string) = $newoffset; 从此位置开始搜索匹配
i 忽阅模式中的大小写
m 将待匹配串视为多行
s 将待匹配串视为单行
o 仅只执行一次变量替换
x 忽阅模式中的空白
8)匹配符号的优先级
() 模式内存
+ * ? {} 出现次数
^ $ \b \B 锚
| 选项
9) 扩展匹配模式
(?pattern) 其中c是一个字符,pattern时起作用的模式或子模式
1、(?:pattern)不存储括号内的模式匹配内容
如/(?:a|b|c)(d|e)f\1/中的\1表示已匹配的d或e,而不是a或b或c。
2、 /(?option)pattern/内嵌模式选项
通常模式选项置于其后,有四种选项:i、m、s、x可以内嵌使用,等价于/pattern/option
如/(?i)[a-z]+/ = /[a-z]+/i
3、(?#注释)模式注释
if ($string =~ /(?i)[a-z]{2,3}(?#match two or three alphabetic characters)/
{....}
4、(?)取消贪婪
"a12b38b" /a.*/ 全部匹配,当/a(.*?)b/时匹配a12b
同样有*?,+?,??,{x}?,{x,}?,{x,y}?
5、/pattern(?=string)/肯定的和否定的预见匹配 ?= ?!
例题1
$line="block1 first block2 second block3 third";
$line =~ /block\d(.*?)(?=block\d|$)/g;
print $1;
例题2 使用while
$line = "begin begin begin ";
while($line=~ /begin(.*?)(?=begin|$)/sg)
{push(@blocks,$1;}
10)替换操作
s/pattern/replace/
替换操作符的选项:g,i,m,o,s,x,e
e 替换字符串作为表达式
$string = "0abc1";
$string =~ s/[a-zA-Z]+/$& x 2/e;
#now $string = "0abcabc1"
11)模式定界符
模式定界符为反斜线/,但其可用字母m自行指定,
m!/u/jqpublic/perl/prog1! 等价于/\/u\/jqpublic\/perl\/prog1/
quotemeta('ab') = \a\b 自动加反斜线
第九章:格式化输出
1)格式的使用
将系统变量$~设成所要使用的格式,调用函数write。
#!/usr/bin/perl
$~ = "MYFORMAT";
write;
format MYFORMAT =
===================================
Here is the text I want to display.
===================================
.
2)输出到其他文件
write将结果输出到STDOUT,输出到任意其他的文件中有两个方法:
1、write(MYFILE)
这样,write就用缺省的名为MYFILE的打印格式输出到文件MYFILE中,但这样就不能用$~变量来改变所使用的打印格式。系统变量$~只对缺省文件变量起作用。
2、改变缺省文件变量,改变$~,再调用write,例如:
select(MYFILE);
$~="MYFORMAT";
write;
3)格式控制符
@<<< 左对齐输出
@>>> 右对齐输出
@||| 居中对齐输出
@##.### 固定精度数字
@* 多行文本
format MYFORMAT =
===================================
Here is the text I want to display.
===================================
.
open(F,"quote");
@quotation = ;
close(F);
$quotation = join("",@quotation);
$~ = "QUOTATION";
write;
format QUOTATION =
Quotation for the day:
-------------------------
~ ^<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
$quotation
~ ^<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
$quotation
~ ^<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
$quotation
-------------------------
.
format QUOTATIONS =
Quotation for the day:
-------------------------
~~ ^<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
$quotation
-------------------------
.
3)分页
页眉:filename_TOP的格式表示页眉,例如给标准输出文件定义页眉:
format STODOUT_TOP =
Consolidated Widgets Inc. 1994 Annual Report
在页眉的定义中也可以包含格式,如当前页码,存储在$%中,如:
format STDOUT_TOP =
Page @<<.
$%
.
$^改变定义页眉的打印格式名,$^只对当前缺省文件起作用
$=每页的长度 缺省每页长度为60行,$= =66;#页长设为66行
$-当前行到页末之间的行数,当$-达到0时, 就开始新的一页。
分页时不用print函数,当用write输出时,perl解释器跟踪每页的当前行号,对print不计算。如果使用print就会使行过长,可以调用系统变量$-.
print("Here is a line of output\n");
$- -=1;
4)printf函数
第十章 函数
1)子程序(函数)定义
带有原型说明的子程序定义:
sub subroutine ($$) { #需要两个简单变量的参数
statements;
}
()中的符号表示参数的类型。以一个字符表示参数。
$简单变量 @列表 %散列
&匿名子程序 *引号
前加\为强制类型一致。 ;分隔必须的参数和可选参数。
\@$;$ 表示第一个参数为列表,第二个参数为简单变量,第三个参数简单变量可选。
2)使用别名或引用传递数组
用别名的方法可以传递多个数组,并能区分数组分界。如:
@array1 = (1,2,3);
@array2 = (4,5,6);
&two_array_sub(*array1,*array2);
sub two_array_sub {
my(*subarray1, *subarray2) = @_;
}
在该子程序中,subarray1是array1的别名,subarray2是array2的别名。
引用:不要对同名变量生效
&two_array_sub(\@array1,\@array2);
sub two_array_sub {
my ($subarray1, $subarray2) = @_;
}
引用是简单变量。要传递给简单变量。
使用引用@$subarray1。$subarray[1]->[0]。
#!/usr/bin/perl
print "1.函数可放在任何地方。\n";
while (1) {
&readaline;
last if ($line eq "q\n");
sub readaline {
$line = ;
}
print ($line);
}
print ("done\n");
<>;
print "2.用别名传递\n";
$foo = 26;
@foo = ("here's","a","list");
&testsub (*foo);
sub testsub {
local (*printarray) = @_;
$printarray = 61;
}
print "$foo\n";
<>;
3)调用子程序
1、&标准调用:&subname(1,2);
无论子程序定义在什么地方都可以用&调用子程序。
2、常用调用:subname(1,2);
只有在调用之前已经定义的子程序才可以省略&
sub subname{} ... subname;
3、前向引用:先声明,再调用,在定义
sub subname;
subname(1,2);
sub subname{...}
4、用do调用: do subname(1,2);相当于&subname(1,2);
5、引用: &$subref(1,2); &不能省略。
6、子程序调用可省略():subname(1,2) subname 1,2。但可能引起优先级问题。
4)递归调用
子程序可以互相调用,当调用子程序本身时,即成了递归子程序。
递归子程序有两个条件:
1、除了不被子程序改变的变量外,所有的变量必须是局部的。
2、该子程序要含有停止调用本身代码。
print "4.递归\n";
sub f{
my $a = shift;
$a==1?1:$a*f($a-1);
}
print f(10);
5)预定义的子程序
perl5预定义了三个子程序,分别在特定的时间执行,你可以自己定义它们,以特定时间执行所需的动作:
BEGIN子程序在程序启动时呗调用;
END子程序在程序结束时被调用;
AUTOLOAD子程序在找不到某个子程序时被调用。
BEGIN {
print("Hi! Welcome to Perl!\n");
}
AUTOLOAD {
print("arguments password: @_\n");
}
第十一章 引用
1)引用的创建
用\创建变量
简单变量的引用:$var = 22;$ref = \$var;连续引用:$rr=\\$var,访问$$$rr;
常量的引用: $ref=\3.14;
数组的引用: $ref=\@ARGV;
散列的引用: $ref=\%ENV;
函数的引用: $ref=\&func; (func的定义在其他位置),不要(),当\$func()时为执行函数,返回值再引用。
文件的引用: $ref=\*STDOUT;
匿名数据的引用:$ref=[1,2,['a','b']];
匿名散列的引用:$ref={'a'=>1,'b'=>2};
匿名函数的引用:$ref=sub{print "anonymous func";} 不用函数名
每个变量都有引用计数,有引用指向的变量计数增加。最初引用的变量销毁了,引用仍可使用:
{ my $a ="hello world"; $a=\$a;} print $$a;
创建a时引用计数为1,$ra引用后计数为2,超出作用域后a销毁,计数为1,内存未回收。引用和变量要同时销毁(超出作用域)或把引用赋与一个值,循环引用无法释放内存。
#!/usr/bin/perl
print "1.引用的变量销毁,仍可引用\n";
{
my $ra;
{
my $a = "hello world";
$ra = \$a;
}
print "ref=$$ra a = $a\n";
}
print "ref=$$a\n";
2)引用的使用
简单变量: $$ref ${$ref}
数组: @$ref @{$ref}; 元素:$$ref[0] $ref->[0];
散列: %$ref %{$ref} 元素:$$ref['a'] $ref->['a']
函数: &$ref(a,b) $ref->(a,b)
文件: $ref
${}内部可以是表达式,结果为$ref
->只用于非简单变量
引用可相互赋值: $ref1=$ref
引用会改变指向的变量的值:$a=1;$ref=\$a;$$ref++->$a=2
引用可还原为普通变量:$ref=1;
3)Ref()与引用的显示
ref($a):如果$a不是引用为假,时引用为真。值如下:
SCALAR 简单变量的引用
ARRAY 数组的引用
CODE 代码(函数)的引用
REF 引用
GLOB 类型通配
print $ref返回类型+地址 HASH(0x809C09D)
4)类型通配typelob
包的全局变量存在一个符号表中,可查找和定位。每个变量一个入口,每个入口包含所有类型的名字,如$name,@name,%name,&name,文件name,格式name。这个入口名为类型通配*name。代表所有的类型。
也可将类型通配看成一个散列,关键字为类型SCALAR,ARRAY,值为变量(入口的变量名为散列名name,name{ARRAY}=@name)。则*name{SCALAR}为$name的引用,使用可$$name或${*name}、@{*name}
类型通配可以赋值。*newname=*name,则newname的变量成为name的变量的同义词。一个变量有两个名字,$name也是$newname。
5) 类型通配的应用
1、创建常量变量: *PI=\3.14;再修改PI时$PI=3;产生错误。
2、匿名结构起名:my $anony=[1,2,3]; *name=$anony; print @name;
3、引用文件句柄:把类型通配(其中包括文件变量)赋给简单变量,在文件上下文使用。
my $out=*STDOUT; print $out 'name';
函数中传递文件句柄:
把文件名传递进去,在函数内重新打开。
将类型通配传入,$f=*STDOUT;func($f);整个类型通配传入。
先得到类型通配的引用,再将引用传入。
my $out=*STDOUT;$f=\out;func($f); ===>$f=\*STDOUT;
4、只改变简单变量: *newname=\$name. $name和$newname一样,是别名。但@newname,@name不 一样
5、做为函数参数传递时类型通配最快,但对类型通配操作可改变变量的值。
foreach $f(10,20,30) {foo(*f);}
sub foo{local (*g)=@_;$g++;} 出错,对常量10自增
print "2.作用域外地局部变量\n";
sub generate_greeting {
my($greeting) = "hello world";
return sub {print $greeting};
}
$rs = generate_greeting();
&$rs;
sub generate_greet {
my($greeting) = @_; # $greeting primed by arguments
return sub {
my($subject) = @_;
print "$greeting $subject \n";
}
}
$rs1 = generate_greet("hello");
&$rs1("world");
sub even_number_printer_gen {
my($input) = @_;
if($input%2) {$input++};
$rs = sub {
print "$input ";
$input += 2;
};
return $rs; #Return a reference to the subroutine above
}
$iterator = even_number_printer_gen(31);
for ($i=0; $i<10; $i++) {
&$iterator();
}
print "\n";
第十二章 Perl包和模块
1)符号表
包的变量和子程序存在符号表中。
在程序中查找符号表可用数组%package::,package为符号表所属包名,查到的是变量名。
$main::{$key}变量名
${$main::{'a'}}得到变量$a的值。
#!/usr/bin/perl
$a = 1;
$b = 2;
foreach $key (keys %main::)
{
print "\$$key => $main::{$key}\n";
}
print ${$main::{'a'}};
print "\n";
package sep_test;
my $sep = ' ';
sub set_sep { #设置分隔符,返回診055来的分隔符
my $prev_sep = $sep;
if (@_) {$sep = $_[0] }
return $prev_sep;
}
sub flip_words {
my $line = $_[0];
my @words = split($sep,$line);
return join($sep, reverse @words);
}
package main;
$line = "a:b:c";
$sep_save = sep_test::set_sep(':');
print sep_test::flip_words($line);
print "\n";
2)模块定义
多数大型程序都分割成多个部件,每一个部件通常含有一个或多个子程序及相关的变量,执行特定的一个或多个任务。集合了变量和子程序的部件称为程序模块。
perl5中用包来创建模块,创建包并将之存在同名的文件中。
如:名为Mymodule的包存储在文件Mymodule.pm中
package Mymodule;
require Exporter;
@ISA=qw(Exporter);
@EXPORT= qw(myfunc1 myfunc2);
@EXPORT_OK=qw($myvar1 $myvar2);
sub myfunc1 {$myvar1 +=1;}
sub myfunc2 {$myvar2 +=2;]
1;
前面时模块通常包含的声明,后面是变量和函数的定义。
阅读(1223) | 评论(0) | 转发(0) |