前置零的写法只用于表示数字直接量,不能用于字符串和数字间的自动转换。
养成加上use utf8;
的习惯。
反斜线后面跟反斜线或单引号
;组合 | 意义 |
---|---|
\n | 换行 |
\t | 水平制表符 |
\r | 回车 |
\f | 换页符 |
\b | 退格 |
\a | 系统响铃 |
\e | 跳出(ASCII编码的转义字符) |
\\ |
反斜线 |
\“ |
双引号 |
\l | 将下个字母转为小写 |
\L | 将它后面的所有字符都转为小写,直到\E 为止 |
\u | 将下个字母转为大写 |
\U | 将它后面的所有字符都转为大写,直到\E 为止 |
\E | 结束\L、\U和\Q开始的作用范围 |
操作符可以使用句点符号.
进行拼接!
#!/usr/bin/perl
use warnings;
#!/usr/bin/perl -w
-w
选项!use diagnostics;
报告核心内容和其他语言一样,只是perl的变量需要拿钱买来,形如$fred
say
代替print
输出结果perl -E 'say q(hello, world)' [255]
hello, world
变量内插
有时候又叫双引号内插
!
lt
:less than
gt
:greater
eq
:equal
比较 | 数字 | 字符串 |
---|---|---|
相等 | == | eq |
不等 | != | ne |
大于 | >= | lt |
小于 | < | gt |
小于或等于 | <= | le |
大于或等于 | >= | ge |
$line =
chomp函数
的返回值是移除的字符数
chomp($text = );#读取不带换行符的输入
#等价于
$text = ;
chomp($text);
ubdef
作为数字、字符串使用时会被视作数字零
、空字符串
defined函数
:判断某个字符串是否为空,如果是undef,返回假!
注意$fred[0]
与fred
是两个不同的东西
如果数组定义如下:
$name[0] = 'a';
······
$name[88] = 'asd';
最后一个元素的索引可以是$#name
和-1
(1, 2, 3) #包含三个数字的列表
(1,"fred", 2) #列表内元素存储格式灵活
(1..100) #从1到100的整数序列
qw
表示为quoted word
用引号引用的词或 quoted by whitespace
用空白引用的词;("fred", "barney", "betty", "wilma", "dino")
# 等价的几种写法,少了很多引号,方便使用!
qw( fred barney betty wilma dino )
qw! fred barney betty wilma dino !
qw{ fred barney betty wilma dino }
qw[ fred barney betty wilma dino ]
qw/ fred barney betty wilma dino /
qw< fred barney betty wilma dino >
qw# fred barney betty wilma dino #
······
删除
和增加
数组末尾元素删除
和增加
数组开头元素splice 最多接收4个参数,分别为目标数组
,操作数组的开始索引
,操作的元素个数
,替换的元素
$_
数字 + 数组
得到的是 数字
,数组名与数字进行比较时,数组名返回的是数组的长度reverse数组
操作,接收的类型不同,得到的内容就不同!数组接收
,以数组元素
为最小单位翻转标量接收
,以最小字符
为最小单位翻转chomp
,reverse
,print
调用子程序
一般需要加上&
sub marine {
$n += 1; # 全局变量$n
print "Hello, sailor number $n!\n"
}
都是全局变量
;呼叫子程序
;&
就可以调用,如调用上面的子程序可以用&marine;
返回值
简化为,返回子程序执行过程中最后一次运算的结果
@_
;&max(10,15);
这样的形式进行传参调用!sub max {
if(@_[0] > @_[1]){
$_[0];
} else {
$_[1];
}
}
my
定义私有变量,如下所示sub max {
my($m, &n); # 该语句块中的新私有变量
($m, &n) = @_; # 将该参数赋值给变量
if ($m > $n) { $m } else { $n } # 只有写成一行时,内部的分号才可以省略
}
sub max {
my($m, &n) = @_; # 对子程序的参数命名
if ($m > $n) { $m } else { $n } # 只有写成一行时,内部的分号才可以省略
}
sub max {
if (@_ != 2) {print "WARNING!应该传入两个参数!"}
my($m, &n) = @_; # 对子程序的参数命名
if ($m > $n) { $m } else { $n } # 只有写成一行时,内部的分号才可以省略
}
选择比较法
,需要理解的就是@_
和$_
;@_
:子程序参数列表$_
:foreach循环读到的值#!/usr/bin/perl -w
sub max{
my($max_so_far) = shift @_;
foreach (@_) {
if ($_ > $max_so_far) {
$max_so_far = $_;
}
}
$max_so_far;
}
$maximum = &max(3, 5, 10, 4, 6);
print $maximum;
my($num) = @_; # 列表上下文,和($num) = @_;相同
my $num = @_; # 标量上下文,和 $num = @_;相同
my
use strict;
:强制使用严格、良好的编程风格use v5.12
:自动加载strict编译指令use strict;
&
:编译器能明显感知到调用的是子程序&
state
,在子程序中,可以一直存在,小编认为是c语言形式
的static的修饰,仍然在全局区!表现形式越来越像c语言函数的写法
!
与Perl的默认变量$_
之间并无直接关联!comp
:截掉最后的换行符defined
:可以用来判断是否读取到末尾!while( ) {
print "I saw $_";
}
foreach( ) {
print "I saw $_";
}
foreach是先把数据全部读进来
;而while是读一行执行一行
;如果要处理400MB数据,估计还是选择while好一点!<>
的名字竟然是Larry的女儿命名的!while(<>){
chomp;
print "It was $_ that I saw!\n";
}
while(defined($line = <>)){
chomp($line);
print "It was $_ that I saw!\n";
}
|
==等特殊字符,就会引发管道等特殊操作。<<>>
双钻石操作符,功能没变钻石操作符
并不会检查命令行参数,其实也只是把命令行参数存放到@ARGV
中@ARGV
的内容,强制修改钻石操作符要读取的内容@ARGV = qw{larry moe curly}; #强制让钻石操作符只读取这三个文件
while(<>){
chomp;
print "It was $_ that I saw in some stooge-link file!\n"
}
print @array;
print “@array”;
print
加括号和不加括号的区别,注意!printf
使用后面的括号是选择性的,如果加上,和C语言就一样了!参数宽度
也可以作为参数
另外指定!#!/usr/bin/perl -w
use strict;
use warnings;
print "Hello world\n";
printf("这里直接是以字符串的格式输出的:\n");
printf "%*s\n", 10, "wilma";
printf("%*s\n", 10, "wilma");
printf("注意,此处参数宽度用参数传入:\n");
printf "%*.*f\n", 6, 2, 3.1415926;
printf("%*.*f\n", 6, 3, 3.1415926);
Hello world
这里直接是以字符串的格式输出的:
wilma
wilma
注意,此处参数宽度用参数传入:
3.14
3.142
my @items = qw{ wilma dino pebbles };
printf "printf输出添加括号:\n";
printf("The items are:\n".("%10s\n" x @items), @items);
printf "printf输出不加括号:\n";
printf "The items are:\n".("%10s\n" x @items), @items;
printf输出添加括号:
The items are:
wilma
dino
pebbles
printf输出不加括号:
The items are:
wilma
dino
pebbles
I/O
操作,6个保留的文件句柄:STDIN
、STDOUT
、STDERR
、DATA
、ARGV
、ARGVOUT
open CONFIG, 'dino'; # 可读可写
open CONFIG, '; # 只读
open BEDROCK, '>fred';# 可写
open LOG, '>>logfile';# 可追加写
open CONFIG, 'dino'; # 可读可写
open CONFIG, '<', 'dino'; # 只读
open BEDROCK, '>', 'fred';# 可写
open LOG, '>>:encoding(UTF-8)', 'logfile';# 可追加写,还可以指定特定编码
binmode
,直接以二进制数据流的方式读写。即使在二进制文件中碰巧出现内部编码和换行符相同的字符,也不会将其当做文本文件中的换行符来处理。my $success = open LOG, '>>','logfile'; # 通过返回值可以判断是否成功?
if(!$success){
# open 操作失败
}
close
,就如C中,有malloc就要有free;C++中,有new就要有delete;die
函数的参数是要发出的错误信息文本,一般会输出到标准错误流,同时让程序退出运行!$!
记录的是程序最后返回给操作系统的错误代码!die
也是由linux中系统函数perror
封装的,但只是猜测if(! open LOG, '>>', 'logfile') {
die "Cannot create logfile:$!";
}
die
相比,warn
不会终止程序的运行!use autodie;
这种声明,就会自动判断!sprintf
print LOG "Captain's log, stardate 3.145159\n" #输出到文件句柄 LOG
printf STDERR "%d percent complet.\n", $done/$total * 100;
STDOUT
,我们可以使用select BEDROCK;
格式来进行切换输出句柄say
函数名字
之前有一个美元符号
,之后有一个花括号
$hash{$some_key}
%
作为前缀,%hash
=>
左边是键,右边是值;my %hash = ('a' => 1, 'b' => 2, 'c' => 3);
my @k = keys %hash;
my @v = values %hash;
my $count = keys %hash; # 返回键值对的个数
if(%hash) {
print "hash 不为空";
}
each
,每次调用都会返回一个键,一个值while (($key, $value) = each %hash) {
print "$key => $value\n";
}
foreach $key (sort keys %hash){
$values = $hash($key);
print "$key => $value\n";
# 或者,可以略去额外的 $value 变量
# print “$key => $hash{$key}\n”;
}
if (exists $hash{"key"}){
# 存在
}
foreach $person (sort keys %books) {
if ($books{$person}) {
print "$person has $books{$person} items";
}
}
%ENV
里面$_ = "yabba dabba doo";
if (/abba/) {
print "It matched\n";
}
.
能匹配除换行外的任意单个字符?
:前一个字符出现n次或0次*
:前一个字符出现n次或0次,常用于匹配不固定长度的空白字符.*
:贪婪匹配,可以匹配任意非换行字符任意次( )
将模式字符串分组(.)\1
:匹配连续出现的两个同样字符|
:或的关系[a=z] # a到z的全部小写字母
[-a] # 连字符 或者 a
[^n-z] #不是n到z的字符
[a]
的相反形式可以是[^a]
简写 | 匹配 |
---|---|
\d | 十进制数字 |
\D | 非十进制数字 |
\s | 空白字符 |
\S | 非空白字符 |
\h | 水平空白字符(Perl 5.10起支持) |
\H | 非水平空白字符(Perl 5.10起支持) |
\v | 纵向空白字符(Perl 5.10起支持) |
\V | 非纵向空白字符(Perl 5.10起支持) |
\R | 一般化的行结尾符号(Perl 5.10起支持) |
\w | 单词字符 |
\W | 非单词字符 |
\n | 换行符(不是真正的简写) |
\N | 非换行符(Perl 5.18 起属于稳定特性) |
\A
:匹配字符串的绝对开头\z
:匹配字符串的绝对末尾\b
:单词锚位,匹配单词边界m( )
,m< >
,m{ }
,m[]
,其中选择斜线作为定界符时,一般省略前面的m,变成了/ /
/i
进行大小写无关的匹配/s
匹配任意字符/.*/s
:可以匹配到换行符/s
修饰符,可以使用[\D\d]
,[\S\s]
等,原理就是数字字符
以及非数字字符
组合就是任意字符。/x
加入辅助空白字符if (/barney.*fred/is){# 同时使用 /i 和 /s
# 匹配成功
}
if (m{
barney
.*
fred
}isx){ # 或同时使用 /i 、 /s 和 /x
# 匹配成功
}
^
与\A
一样,$
与\z
一样/m
修饰符,/^/m
就会匹配字符串开头和换行符之后的内容(就是每行开头)$_
,我们可以使用绑定操作操作符=~
指定要匹配的目标文本。()
进行捕获?:
,此时的括号仅用于分组,不再捕获匹配字符串。use v5.10;
my $names = 'Fred or Barney';
if ($names =~ m/(? \w+) (?:and|or)(? \w+)){
say "I saw $+{name1} and $+(name2)";
}
/p
可以对当前的表达式开启类似的自动捕获变量,变成了${^PREMATCH}
,${^MATCH}
,${^POSTMARTCH}
正则表达式特性 | 示例 |
---|---|
元括号(分组或捕获) | (···),(?:···),(?···) |
量词 | a*,a+,a?,a{n,m} |
锚位和字符序列 | abc, ^, $, \A, \b,\z,\Z |
择一 | a|b|c |
原子 | a,[abc],\d,\l,\g{2} |
#!/usr/bin/perl
while (<>) { # take one input line at a time
chomp;
if (/YOUR_PATTERN_GOES_HERE/) {
print "Matched: |$`<$&>$'|\n"; # the special match vars
} else {
print "No match: |$_|\n";
}
}
s///
进行替换操作s/st1/st2; #试图将st1替换为st2
/g
进行全局替换s/\s+/ /g; # 将任意连续的空白转换成单一空格
s/\A\s+//g; # 将开头的空白字符替换成空字符串
s/\s+\z//g; # 将结尾的空白字符替换成空字符串
s/\A\s+|\s+\z//g; #去除开头和结尾的空白字符
m//
和 qw//
一样,可以改变s///
的定界符/g
修饰符外,我们还可以把用在普通模式匹配中的/i
、/x
和/s
修饰符用在替换操作中=~
为s///
指定不同的替换目标my $original = 'Fred ate 1 rib';
my $copy = $original;
$copy =~ s/\d+ ribs?/10 ribs/;
(my $copy = $original )=~ s/\d+ ribs?/10 ribs/;
/r
字符串,就会保留原来字符串中的值不变,把替换结果作为替换操作的返回值返回use v5.14;
my $copy = $original =~ s/\d+ ribs?/10 ribs/r;
\U
将它后面的所有字符转成大写的\L
将它后面的所有字符转成小写的\E
关闭大小写转换的功能;\l
和\u
,它们只会影响紧随其后的第一个字符;\u
与\L
来表示"后续字符全部转为小写的,但首字母大写”s/\(\(\(Fred/fred/
# 使用\Q简化形式
s/\Q(((Fred/fred/
\
my @fields = split /separator/, $string;
my @fields = split /:/,"abc:def:g:h"; # 得到("abc","def","g","h")
my @fields = split /:/,":::a:b:c:::" # 得到("","","","a","b","c")
my @fields = split /:/,":::a:b:c:::",-1 # 得到("","","","a","b","c","","","")
split
会以空白字符分割$_
中的字符串;my @fields = split; # 基本等效于split /\s+/, $_;
my $x = join ":",4,6,8,10,12; # $x 为 “4:6:8:10:12”
my @values = split /:/,$x; # @values 为(4,6,8,10,12)
my $z = join "-", @values; # $z为 “4-6-8-10-12”
if
条件为真时执行,unless
条件为假时执行if else
改成了unless else
until
print "$n is a negative number.\n" if $n < 0;
if($n < 0) {
print "$n is a negative number.\n";
}
{ }
主要是为变量限制作用域,和c++一样elseif
for
,若没有分号,就把他当做foreach
? :
expression ? if_true_expr : if_false_expr
短路操作符
可以改为三目运算符
!&&
、||
、//
、?:
都是根据左边的值确定要不要执行右边的表达式Cwd
模块,查看当前的工作目录是哪个use v5.10;
use Cwd;
say "The current working directory is ",getcwd();
File::Spec
实现相对路径和绝对路径之间的相互转换\chdir
:和shell中的cd一个意思chdir '/etc' or die "cannot chdir to /etc :$!";
File::HomeDir
模块去往特定用户的主目录,他支持大部分操作系统。glob
my @all_file = glob '*';
my @pm_file = glob '*.pm';
glob
并非唯一选择,我们可以用File::Glob
模块提供各式兼容和扩展的文件名通配。my @all_files = <*>; # 效果和这样的写法完全一致: my @all_files = glob "*";
my $dir = '/etc';
my @dir_file = <$dir/* $dir/.*>;
my $dir_to_process = '/etc';
opendir my $dh, $dir_to_process or die "Cannot open $dir_to_process:$!";
foreach $file (readdir $dh) {
print "one file in $dir_to_process is $file\n";
}
closedir $dh;
DIR
my $dir_to_process = '/etc';
opendir DIR, $dir_to_process or die "Cannot open $dir_to_process:$!";
foreach $file (readdir DIR) {
print "one file in $dir_to_process is $file\n";
}
closedir DIR;
unlink
:unlink 'slate', 'bedrock','lava';
unlink qw{slate bedrock lava};
unlink glob '*.o';
unlink
返回的是成功删除的文件数目,我们可以把他们放到循环依次删除并检查foreach my $file (qw(slate bedrock lava)) {
unlink $file or warn "failed on $file:$!\n";
}
rename 'old','new';
=>
:.old
结尾的文件改名为以.new
结尾?foreach my $file (glob "*.old") {
my $newfile = $file;
$newfile =~ s/\.old$/.new/;
if (-e $newfile) {
warn "can't rename $file to $newfile: $newfile exists\n"
} elsif(rename $file => $newfile) {
# 改名成功,什么都不需要做
} else {
warn "rename $file to $newfile failed:$!\n";
}
}
my ($newfile = $file) =~ s/\.old$/.new/;
/r
修饰符,use v5.14;
my $newfile = $file =~ s/\.old$/.new/r;
软链接
这个说法吗?(之前有老师强调过,没有软链接这一说,是符号链接和硬链接)mkdir 'fred', 0755 or warn "Cannot make fred directory: $!";
foreach my $dir(qw{fred barney betty}) {
rmdir $dir or warn "cannot rmdir $dir:$!\n";
}
File::Temp
模块chmod
不支持linux中a+x
这种格式,除非从CPAN安装了File::chmod
.chmod 0755, 'fred','barney';
chown $user, $group, glob '*.o';
my $now = time;
my $ago = $now - 24 * 60 * 60; # 一天的秒数
utime $now, $ago, glob '*'; # 将最后访问时间改为当前时间,最后修改时间改为一天前
my $where = index($stuff, "wor");
my $part = substr($string,$initial_position, $length);
my $money = sprintf "%.2f", 2.4997;
my @descending = sort {$b <=> $a} @some_numbers;
my %score = ("barney" => 195, "fred" => 205, "dino" => 30);
my @winners = by_score keys %score;
my %score = (
"barney" => 195, "fred" => 205,
"dino" => 30, "bamm-bamm" => 195,
);
my @winners = by_score_and_name keys %score;
sub by_score_and_name {
$score{$b} <=> $score{$a} #先按照分数降序排列
or
$a cmp $b #分数相同的再按名字的ASCII码序排列
} @winners
@patron_IDs = sort{
&fines($b) <=> &fines($a) or
$items($b) <=> $items($a) or
$family_name{$a} cmp $family_name{$b} or
$personal_name{$a} cmp $family_name{$b} or
$a <=> $b;
} @patron_IDs;