perl编程综合小骆驼学习笔记
Posted oddxix
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了perl编程综合小骆驼学习笔记相关的知识,希望对你有一定的参考价值。
接下来几天系统学完Linux就可以入手Python了,有点小紧脏嘻嘻
1.perl入门
perl全名是practical extraction and report language,实用摘录于报表语言。主要用于文字处理,具有容易使用,不受限制,速度快,代码有点难看等特点。我觉得最牛逼的地方在于他是不封闭的,你可以看到他的代码。
脚本的编写:
例1:
#! /usr/bin/perl
print "hello,world!\n";
#! /usr/bin/perl
use 5.010
say "hello,world!";
这是两个代码,但输出的结果一样。\n是换行符的意思,打出这个结果后,光标落在下一行,而用say就可以不用输入\n而自动换行,但是有一个条件,必须是perl 5.10版本以后,如果不是就,就得提醒一下,通过use 5.010告诉解释器,但是解释器识别的是小数点后三位,所以perl 5.10版本得写成5.010
这里可以通过perl -v来看你版本,我的是5.14.2
脚本的命名:
Perl程序并不需要什么特殊的文件名或拓展名,甚至不用拓展名就最好不要用。就是怕用其他的程序改写后以免引起误解。但是呢,我一般还是会用.pl,至少提醒自己这个文件是一个脚本啊,你觉得呢
脚本的运行:
你可以直接在终端中 :perl my_pro.pl #my_pro是你编写的脚本的名字
也可以chmod a+x my_pro 把该文件变成一个可执行的程序,然后cd到该文件夹,同多./my_pro来运行,淡然如果是可执行的文件,在修改的时候得注意了,我之前提到过,打开后i修改,esc后, :wq来保存
CPAN
comprehensive perl archive network,里面有很多perl的源代码,各种下载
2.Perl—标量变量
Perl标量(scalar)是称呼单个的事物,可以是数字,也可以是字符串。变量即为存储一个或多个值的容器的名称。标量变量为仅仅存放一个值的变量。
首先,我们来聊一下perl常见的单引号双引号的区别:
1,两者都是用来让perl识别字符串的开始和结尾 “fred”和‘fred’效果一样
2,单引号 也只有在反斜线后面接单引号或反斜线时,才表示转义。要使用\则需要在前面加一个\来转义,要使用'则需要在前面加一个\来转义,例如:‘\'\\' 表示单引号后接一个反斜线
3,双引号 一般用作转义或这是使用变量内插
\在里面有很强的转义功能,比如\n表示换行,一般结尾都需要来个这个
\f换页 ……
$meal="bro steak";
$barney="fred ate a $meal";
$barney='fred ate a'.$meal; 这两种写法效果一样,其中.表示为链接字符串的操作符。所以上面那个看上去更简洁嘛
结合着例子来说明吧
第一个例子:提示用户输入半径来求周长
#! /usr/bin/perl #告诉脚本Perl在哪里运行
use warnings; #有错误的话,就提醒,也可以跟上面合并#! /usr/bin/perl -w
$pi=3.141592654; #定义标量变量$pi的值为
print "What is the radius?"; #提示输入半径
chomp($radius=); #为行输入,其返回的字符串一般在末尾都会有换行符,如果字符串后面有两个以上的换行符,chomp()仅仅删除一个
print "The circumeference of acircle of radius $radius is $circ.\n"; #后面不输入\n的话结果末尾光标提示有误
第二个例子:当输入的半径小于0时,输出的结果为0,不为负数。
#! /usr/bin/perl
use warnings;
$pi=3.141592654;
print "What is the radius?";
chomp($radius=);
$circ=$pi*2*$radius;
if($radius<0){
print "0\n"
}else{
print "The circumeference of acircle of radius $radius is $circ.\n";
}
这里面就是多了一个if语句,如果()里面的,就怎样,否则……
第三个例子:提示用户输入两个数字,然后输出两者的乘积
#! /usr/bin/perl
use warnings;
print "What is the one?";
chomp($one=);
print "What is the two?";
chomp($two=);
$three=$one*$two;
print "The result is $three\n";
第四个例子:提示输出一个字符串和一个数字,使用x操作符
#! /usr/bin/perl
use warnings;
print "plese enter a string:";
chomp($one=);
print "please enter a number of times:";
chomp($two=);
$three=$one x $two;
print "The result is $three\n";
each操作符:
my @rocks=qw / bedrock slate rubble granite/;
while(my($index,$value)=each @rocks){
say"$index:$value";
}
每次对数组调用each,会返数组中下一个元素所对应的两个值—该元素的索引以及各该元素的值
3.perl—列表和数组
列表是标量的有序集合,数组是存储列表的变量。数组或列表中的每个原书都是单独的标量变量,拥有独立的标量值,这些值是有序的,也就说,从开始到终止元素的先后次序是固定的。并且每个元素都有相应的整数作为索引,此数字从0开始递增,每次加1.
还是来案例来理解这一节的东西吧。
1,写入一个程序,读入一些字符串(每行一个,)直到文件结尾位置,然后,再以相反的顺序输出这个列表。
#! /usr/bin/perl
use warnings;
print "please enter your string,then press Ctrl+D:\n";
@lines=;
@a=reverse @lines;
print @a;
#在列表上下文中,会返回所有剩下的行,知道文件结尾为止,
#通常可以键入Control+D来告知系统,不会有任何输入了(对于DOS/Windows来说,要用Control+Z)
reverse操作符会读取列表或数组的值,并按相反的次序返回该列表,这个是对..很好的补充,因为6..10代表6到10,但其中..只表示递增的关系。
2写一个程序,读入一数字(每行一个),直到文件结尾为止,然后根据每一个俗子输入的如下名单中相应的人名。
#! /usr/bin/perl
use warnings;
print "please enter some numbers from 1 to 7,one per line,then press Ctrl-D:\n";
chomp(@a=);
@b=qw(fred betty barney dino wilma pebbles bamm-bann);
foreach $_ (@a){
print "$b[$_-1]\n";
};
#chomp会自动去掉每个元素的换行符
qw表示quoted word,perl会把其当作单引号的内的字符串来处理,所以qw构建的列表中,不能像双引号内的字符一样用\n或$fred.其中的空白符(如空格,制表符,换行符),同时还容许其他任何标点符号作为定界符,只要左右的相同,同时如果你要在被圈引的字符串内使用定界符,还可以通过反斜线转义来引入这个字符。
foreach $_ ()就是一个个的找()内的单个字符串,然后单个的字符串定义为$_,其中$_是默认的,可以不写,后面默认,同时也可以写使用其他的标量变量。
$b[$_-1]表示取数组@b中的第$_个元素。无论是列表还是数组,其索引都是从0开始的,所以数组中对应的第一个对象的索引号为0,对于@a其最大的索引为$#a,注意这个数会比数组元素的个数少1.还有一个“负数数组索引值”,最后一个元素的索引值为-1,倒数第二个为-2,一次类推。
@b数组名只能包含标量,不能包含其他数组,所以数组无法成为列表里的元素,只能展开生成元素列表。
3,读入一些字符串(每行一个),知道文件结尾为止,然后按ASCII码顺序来输出所有的字符串。
输出的结果在一行
#! /usr/bin/perl
use warnings;
print "please enter some some strings,one per line,then press Ctrl-D:\n";
chomp(@a=);
@b=sort @a;
print "@b\n";
输出的结果在不同的行
#! /usr/bin/perl
use warnings;
print "please enter some some strings,one per line,then press Ctrl-D:\n";
chomp(@a=);
@b=sort @a;
foreach $b(@b) {
print "$b\n";
}
其中sort就是一个排序操作符,规则是大写字符在小写字符前面,数字排在字母前面,标点符号散落各地,但100,99的排序的时候还是100,99,因为根据默认的排序规则,任何以1开头的字符串会被排在以9开头的字符串之前。
4.perl—数组中元素的修改
对尾部:
pop操作符负责取出数组中最后一个元素并将其作为返回值返回。
@a=5..9
@b=pop@a
其@b为9,@为5..8
或者直接pop@a,也就是删掉@a的最后一个元素
push操作符,用来加入一个元素(或是一串元素)到数组的尾端。
push @a,5; #数组a中最后一个元素加入5
@b=qw/ 9 0 9 0 3/;
push @a,@b; @a得到了5个新元素
对头部:
$a=shift (@b); #@b前一个元素丢失,$a为其第一个元素
unshift同理push
unshift @arrary,@others
对整体:
替换和删除
@a=splice @b,2,4,qw(c b d)
其中@b为处理的数组,2代表的是要操作的一组元素开始位置,其指示索引值,相当于把光标放在了第二个元素的后面,如果仅仅就给出前面两个参数,perl会从给定位置开始一直到末尾的全部元素提取出来并返回。其中4为指定操作的长度。qw(c b d)为要替换的列表,替换的长度不一定要跟拿走的长度相等。
@ab=qw(a b c d e);
@removed=splice @ab,1,2,qw(will);
#删除b,c ;@removed变成(b c);@ab变成qw(a will d e)
增加:
@array=qw( pebbles dino fred barney betty);
@removed=splice @array,1,0,qw(wilma);
#什么元素都不删,@removed变成了qw();@array变成了qw(pebbles wilma dino ...)
5.Perl—子程序
Perl可以让你创建子程序,它让我们可以重复利用已有的代码
例1:写一个求和的子程序,同时检验
#! /usr/bin/perl
use strict; #告诉perl内部的编译器的代码应该稍微严谨一些。也可以通过use 5.012隐式打开,
use warnings;
sub total{ #要定义自己的子程序,可以通过sub,子程序名,花括号封闭起来
my $sum=0;
foreach (@_){
$sum +=$_;
}
$sum;
}
my @fred =qw(1 2 5 7 9);
my $fred_total=&total(@fred); #通过&来调用子程序,如果不引起歧义,可以省略&。()里面是
print "The total of \@fred is $fred_total.\n"; 参数
print "Enter some numbers on seperate lines:";
my $user_total=total();
print "The total of those numbers is $user_total.\n";
所有的子程序都有一个返回值—子程序并没有“有返回值”或“没有返回值”之分。但并不是所有的在子程序的返回值都是有用的。最后一次结果都将自动当初子程序的返回值。在子程序里添加额外的程序代码时,请小心检查最后执行的表达式是哪一个,确定它是你要的返回值。
子程序自动将参数存在了@中,其中第一个参数为$[0],第二个为$[1],一次类推,这些变量和$没有任何关系。其中@_为子程序的私有变量。
perl里面所有的变量都都是全局变量,在程序的任何地方都可以访问他们。可以借助my来创建私有变量。这些变量属于子程序封闭语句块所有,其他地方使用不受影响。my barney,只能申明第一个为私有变量。
return,子程序执行到一半的时候停止执行:
sub which_element_Is{
my($what,@array)
foreach (0..$#array)
if ($what eq $array[$_]){
return $_;
}
}
-1;
}
例2:找出大于平均值的数
#! /usr/bin/perl
use warnings;
use strict;
sub average{
my $sum=0;
my $n=0;
my $average;
foreach (@_){
$sum +=$_;
$n +=1; #也可以通过$n=@_来知道含有多少个元素。
}
$average=$sum/$n;
}
sub above_average{
my @lists; #定义私有变量
my $a=&average(@_); #调用上面的子程序
foreach (@_) {
if ($_>$a){
push @lists,$_; #push往首先加元素
}
}
@lists;
}
my @fred=&above_average(1..10);
print "\@fred is @fred\n";
例3:记录之前都来了那些人
#! /usr/bin/perl
use warnings;
use strict;
use 5.010;
sub greet{
state @names;
my $name=shift;
print"hi $name!";
if (@names){
print "I've seen:@names\n";
}
else{
print "You are the first one here!\n";
}
push @names,$name;
}
greet('fred');
greet('barney');
greet('wilma');
6.Perl—输入和输出
前面已经提到$line=,@line=,即可以过多键盘输入的东西进入到程序中去运行。<>是另一种读取的方式,钻石操作符是行输入操作符的特例,它不是从键盘输入,而是从用户指定的位置读取。
while(defined($line=<>)){
chomp($line);
print "It was $line that I saw!\n";
}
也可以简写为
while(<>){
chomp;
print"It was $_ that I saw!\n";
钻石操作符是用来读取输入的,而输入的内容可以在$_中找到。
钻石操作符会先查看数组@ARGV,然后决定该用那些文件名,如果它找到的是空列表,就会改用标准输入流,例如在前面的程序中加入@ARGV=“”,它就只会去读这里面的文件了。
print @arrary;
print "@arrary";
第一个print语句会一个接一个地打印出数组中的所有的元素,元素之间不会有空格,比如@arrary=qw”fred barney betty”,第一个语句输出的是fredbarneybetty,而第二个输出的是空格隔开的fred barney betty.
如果有换行符,建议还是用第一种,如果不含换行符,用第二种,当然后面可以加\n
printf操作符的参数包含“格式字符串”以及“要输出的数据列表”
例如:printf "Hello,$s;your password expires in %d days!\n",$user,$days_to_die;
出来的结果是:Hello,merlyn;your password expires in 3 days!
最常用的格式:
恰当的数字格式:
printf "g% %g %g\n",5/2,51/17,51**17 # %g会按需要自动选择浮点数,整数甚至指数形式
print "in %d days !\n",17.58 #%d代表十进制的整数,无条件的曲调小数点后面的数字
** 字符的格式**:
printf "m\n",42 #输出的结果看起来像····41(其中·代表空格)
printf "s\n","wilma"; #看起来像·····wilma
printf "%-10s\n","wilma"; #负号是左对齐,结果为wilma·····
printf ".3f\n",6*7+2/3 #%f按需要四舍五入,可以指定字段宽度和小数点位数结果为 ······42.667
要输出真正的%,请用%%
print"%.2f%%\n",5.25/12; # 结果为0.44%
**数组的格式**:
$format="The items are :\n".("%${width}s\n"x@string); #${width}为变量指定的字符宽度,为了 printf $format,@string;格式: 避免混淆,加了{}
文件句柄
代表perl进程与外键之间I/O联系的名称,仅仅是联系的房产,不是文件的名称。建议用全大写字母来命名文件句柄。跟已有的文件柄:STDIN,DTDOUT,STEERR,DATA,ARGV,ARGVOUT不要重名,其他的可以选择自己喜欢的名字。
方式1: perl tac2 <> uuu
方式2 ./tac2 <> uuu
其中tac2为写的脚本, <>中的m为输入的文件 ,uuu为你存放生成的结果的文件名,可以自己取名字。
打开文件句柄:
open CONFIG,’dino’;
open CONFIG,’
open BEDROCK,’.fred’;
open LOG,’>>logfile’;
第一行打开名为CONFIG的文件句柄,让它指向文件dino,也就是打开文件dino,文件中的任何内容都可以从文件句柄CONFIG被督导我们的程序中来。
第二行申明此文件用来读取的,而非写入的
第三行用来创建一个新的文件,打开文件句柄BEDROCK,并输入到新的文件fred中,如果已有该文件,就清除重新建
第四行用来追加的方式打开文件,
open的三个参数形式:
open CONFIG,’<’,’dino’;
open BEDROCK,’>’,$file_name;
open LOG,’>>’,&logfile_name();
这种写法的好处就在于,可以在文件操作模式后面加上冒号,写上编码名称
open CONFIG,’<:encoding(UTF-8)’,’dino’;
关闭文件句柄
close BEDROCK;
通知系统将尚未写入的输出数据写到磁盘,显得工整一些
改变默认的文件输出句柄:
select LOG; #选择LOG作为输出的文件句柄
$| =1; #输出操作之后立刻刷新缓冲区
select STDOUT; #回复到默认的输出文件句柄STDOUT;
print LOG “This is very good!\n”;
例1:反向输出
#! /usr/bin/perl
use warnings;
use strict;
use 5.010;
my @line=<>;
chomp @line;
my @b=reverse(@line);
print "@b\n";
当我在终端运行这个:perl tac m n (m,n为保存有字符串的文件)
为什么没有反向输出的效果呢?求解
当把里面的@改成$后,可以对单个文件处理,反向输出,这是个什么原因呢?
例2:用户自定义输出的字符宽度:
#! /usr/bin/perl
use warnings;
use strict;
my $width;
print"Please enter the number of size,the enter Ctrol +D to end:\n";
$width=<>;
chomp $width;
print"please enter the string,the enter Ctrol +D to end:\n";
my @string=<>;
chomp @string;
my $format="%${width}s\n"x@string;
printf $format,@string;
7.perl—哈希
哈希是一种数据结构,它和数组的相似之处 在于可以容纳任意多的值并能按需取用,而它和数组的不同在于索引方式,数组以数字来索引,哈希则是以名字来索引。哈希的索引值为键(key),并不是数字,而是任意唯一的字符串。这些键和值都是任意的标量,但键总会被转换为字符串。即使哈希包含300万个键值对,从中提取任意的一项数据还是会和原来一样快。但键则必须是唯一的字符串。
它有什么用呢?
按名字找姓
按主机名找IP
按IP找主机名
按单词统计其出现次数(用的比较多)
按用户名统计每个人使用
说白了,哈希就是个极其简单的数据库。
访问哈希元素: $family_name{‘fred’}=’flintstone’;
这和数组的做法类似,只是使用了花括号而非方括号来表示索引值
哈希变量的命名不可以用数字开头。
访问整个哈希 :
%some_hast=('foo',35,'bar',12.4,2.4,'helllo','wilma',1.72,'betty',"bye\n");
对哈希的赋值,等同于在列表上下文中赋值,列表中的元素应该为键值对。
也可以通过 my$inverse_hash=reverse %any_hash 把键值对给范徐过来,最好确认值也是唯一的在使用,不然会弄错。
my %last_name=(
'fred' => 'flintstone',
'dino' => undef,
barney=>'rubble',
betty =>'rubble',
);
任何需要逗号的地方都可以用胖箭头来替代,这对perl来说,并没有多大的区别。使用胖箭头的时候可以省略左边的引号,会自动被引起。同时,在使用哈希额键,如果花括号内只有裸字,两边的引号也可以省略。(无需引号的字符序列,我们称之为裸字bareword,因为它是孤立存在的)
当然注意,$hash{bar.foo}=1; #构成的键名是’barfoo’
my @k =keys \$hash;
my @v=values \$hash;
因为哈希就像一个大酒桶,所以里面的顺序是无法预测的,但是返回的键列表和值列表的顺序还是一致的。
my $count =keys %hash; #得到键值对数
while((\$key,$value)=each %hash){
print "\$key =>$value\n";
}
delete \$books{\$person}; #撤销person的
%ENV 环境变量
修改环境变量
Bourne shell
$CHARACTER=Fred; export CHARACTER
$export CHARACTER=Fred
csh
$ setenv CHARACTER FRED
DOS或者Windows命令
c:>set CHARACTER=Fred
例1:根据姓来找名字(很有意思的),程序名family_name
#! /usr/bin/perl
use warnings;
use strict;
my $s;
my %mily_name=("fred"=>'flintstone',
"barney"=>'rubble',
"wilma"=>'flintstone',
);
print "please enter the family name:\n";
$s=<>;
chomp $s;
print "The ${s}'s name is $family_name{$s}.\n"
例2:程序名为frequence,统计每行一个词汇,这个词汇出现的次数。
#! /usr/bin/perl
use strict;
use warnings;
my ($string,@string,%string);
@string=<>;
chomp @string;
foreach $string (@string){
$string{$string}+=1;
}
foreach $string (sort keys %string){
print"$string has show up $string{$string} times.\n";
}
例3:程序名为ENV,读取%ENV中的键值对,排序,分两列打印,纵向对其。
#! /usr/bin/perl
use warnings;
use strict;
my $longest;
my $key;
my $length;
foreach $key (sort keys %ENV){
my $length=length($key);
if ($length>=$longest){
$longest=$length;
}
}
foreach $key (sort keys %ENV){
printf "%-${longest}s %s\n","$key","$ENV{$key}";
}
注:my操作符只能申明独立的标量,不能用来申明数组或哈希里的元素。
use strict起作用时候才需要申明变量,默认情况下并不需要申明标量。
8.perl—漫游正则表达式
正则表达式(regular expre ssion)是perl内嵌,自成一体的微型编程语言。出现在很多语言中,以及在大多数的程序员文本编辑器中(比如vi和emacs).在perl里通常叫做模式(pattern),用来表示匹配或不匹配某个字符段的特征模板。只要用一个模式就可以将它们干净利落地分成两组:匹配或者不匹配。
在Unix的grep命令中,它会检查哪几行文本匹配到指定的模式,然后输出那几行。
例如: $grep ‘flint.stone’ chapter.txt
如果模式匹配的对象是$_的内容,只要模式写在一对斜线(/)中就可以了,自动去寻找
例如:
\$_="yabba dabba doo"'
if (/abba/){
print;
}
Unicode属性
他们不只是简单的字节序列。每个字符出来字节组合之外,还有属性信息。若要匹配某项属性,只需要把属性名放入\p{PROPERTY}\里面。比如许多字符属于空白符,相应的属性名为space,所以要匹配带有这类属性的字符,可以用\p{Space}.将小写的p改为大写的P,就表示否定的意义,匹配指定属性之外的字符。
. 能匹配任意一个字符的通配符(不能匹配换行符\n),如果要表示点号本身的话,就需要在前面加上反斜线转义。同时,如要匹配真正的\,也需要在前面加上\。
* 用来匹配前面的条目零次或多次的。
+ 匹配前一个条目一次以上。
? 表示前一个条目是可有可无的
() 对字符串来分组
我们可以用反向引用来引用圆括号中的模式所匹配的文字,这个行为我们成为捕获组。
(.)\1 表示匹配连续出现的两个同样的字符。\后面的数字是编号,只要一次点算左括号的序号就可以了
$_="yabba dabba doo";
if (/y((.)(.)\3\2)d\1/){
print;
}
有的时候为了消除反向引用模式的直接量部分的二义性
use 5.010; #这个版本开始才有这个功能
$_="aa11bb";
if (/(.)\g{1}11/){
print;
}
这里面的g{1}就相当于\1,主要是为了避免歧义嘛,同时,也可以用负数,相反的意思。
| 通常读成“或”,要么匹配左边的内容,要么匹配右边的内容。
[] 表示里面的字符集中任何一个,比如[a-z],其中-是连字符,表示从a到z
^ 表示除什么之外,[^a-z]除a到z之外的任意的字符都能匹配
字符的简写
表示任意一个数字的字符集的简写是\d
\s 匹配任意空白符
\w现在被扩展了,表示单词嘛
[\d\D] 表示任何数字或非数字,就是说能匹配到任意的字符。它跟.相比的话,这个同时还包括换行符。
例1:检验已知文件中是否含有fred或者Fred字符,有的话就把这一行打印出来。
#! /usr/bin/perl
use warnings;
use strict;
while(<>){
if(/(f|F)red/){
print ;
}
}
例2:找包含.的字符串,打印出来那一行。这里面相当用了一个转义符
#! /usr/bin/perl
use warnings;
use strict;
while(<>){
if(/\./){
print ;
}
}
例3:打印那些有两个相连且相同的非空字符的行。
#! /usr/bin/perl
use warnings;
use strict;
while(<>){
if(/(\S)\1/){
print ;
}
}
例4:打印出同时出现wilma以及fred的行(注意先后之别)
#! /usr/bin/perl
use warnings;
use strict;
while(<>){
if (/wilma.*fred|fred.*wilma/){
print;
}
}
9.Perl—用正则表达式进行匹配
之前我们看到,正则表示的写法的时候用的是//,比如说/fred/,实际上这是m//的简写,就像前面提到的数组qw//一样。同样的,m也可以任何成对或不成对的定界符,比如说m(fred).
我们可以选择模式中不会出现的字符来作为定界符,比如/http:\/\//,可以写为m%http://%。
常见的修饰符
/i 实现大小写无关的匹配
/s 匹配任意字符 因为.不能匹配换行符,而加上这个后,点号就能匹配任意的字符了
/x 容许在模式里随意地加入空字符
/a 选择ASCII码作为解释方式
/p 只会针对特定的正则表达式开启类似自动捕获变量
/g 全局替换
写法: if (/yes/i)
注意:#是注释符号,如果需要用的话,可以加上\,或者[#]。
这些修饰符可以放在一起,放在模式末尾,不必在意先后顺序。
Perl从5.14开始,有三种字符解释方式,ASCII,Unicode,locale。下面的修饰符分别告诉采取何种方式解释字符。
use5.014
/\w+/a #仅仅表示A-Z,a-z,0-9
/\w+/u #任何Unicode当中定义为单词的字符
/\w+/l #类似ASCII的版本,但单词字符的定义取决于本地化定义
单个/a修饰符表示按照ASCII方式解释简写意义,如果使用两个/a,则进一步表示仅仅采用ASCII当时的大小写映射处理
/k/aai #只匹配ASCII字符K或k,但不匹配开尔文符号
锚位
通过给定锚位,我们可以让模式仅在指定位置匹配
\A锚位匹配字符串的绝对开头
\z锚位字符串的绝对末尾
\Z锚位字符串绝对末尾,但容许出现换行符
\b是单词的边界锚位,它能匹配任何的那次的首位
\B 非单词边界锚位,它能匹配所有\b不能匹配的位置。
^ 表示行首, /m 分别表示锚位与多行的行首和行尾
=~绑定操作符
默认情况下模式匹配的操作对象是_
例如: if ($some_other=~/\brub/){
经典的例子:
#! /usr/bin/perl -w
my $what="larry";
while(<>){
if(/\A($what)/){
print "We saw $waht in the beginning of $_";
}
}
这个例子中我比较喜欢$_,这个代表了输入行,自动被存入的。同时还有变量的内插,当然,如果加上=^就更牛逼了
捕获变量
变量$4的意思是模式中第4对括号所匹配的字符串内容,这个内容和模式运行期间反向引用\4所表示的内容是一样的。但他们并非同一个事物的两种名称:\4反向引用是模式匹配期间得到的结果,而$4则是匹配结束后所捕获的内容的索引。
if (/\s(a-zA-Z)+,/){ #捕获的是空白符和逗号之间的单词
print $1;} #$1为捕获的第一个变量
这些捕获的变量通常存活在下次匹配成功为止。如果需要在数行之外使用捕获变量,通常最好的做法就是将它复制到某个普通变量里。
if (/\s(a-zA-Z)+,/){
my $wilma= $1;
不捕获变量
有的时候,圆括号的加入仅仅是为了分组,所以要关闭它的捕获功能,只需要在左括号的后面加上?:来告诉perl这一对圆括号完全是为了分组而存在的,把变量名留出来
例如: if (/(?:bronoto)?saurus(stedk|burger)/){ #这个里面$1为(stedk|burger)
命名捕获
use 5.010
my $names='Fred or Barney';
if ($names=^m/(?\w+)(?:and|or)(?\w+)/){
say "T sam $+{name1} and $+{name2}";
}
看明白了吗,通过(?PATTERN),其中LABERL可以自行命名,再通过$+{LABEL}来捕获它
在使用捕获标签后,反向引用的用法也随之改变,之前我们用\1或者\g{1}这样的写法,现在我们可以使用
\g{label}的写法
自动捕获变量
$& 字符串实际匹配模式部分会被自动存在
$` 匹配区段之前的的内容存在
$‘ 匹配区段之后的内容存在
但是呢,一旦用了这些自动捕获变量,其他正则表达式的运行速度就会变慢。
我们可以将这个的命名改一下,一下的是在5.10或以上的版本中使用
$& ${^MATCH}来表示
$` ${^PREMATCH}
$‘ ${^POSTMATCH}
例如:
use 5.010;
if ("Hello,there,neighbor"=^/\s(\w+),/p){
print "That actually matched '${^MATCH}'.\n"
}
之前看到的三个量词:* + ?
如果这三个量词都不符合要求,我们还可以使用花括号{}形式指定具体的重复次数范围。
例如 /a{5,15}/其为5到15次的a
优先级
圆括号(分组或捕获) (…)(?:…)(?…)
量词 a*,a+,a?,a{n,m}
锚位和序列 abc,^,$,\A,\b,\z,\Z
折一竖线 a|b|c
原子 a,[abc],\d,\1,\g{2}
有的时候加上括号对弄清优先级有好处,但是圆括号的使用同时也会有捕获功能哦
例1:检测,是否能匹配到match
#! /usr/bin/perl
while (<>){
chomp;
if(/(match)/){
print "Matched: |$`<$&>$'|\n";
}else{
print "No match:|$_|\n";
}
}
例2:检测以字母a结尾的单词,
#! /usr/bin/perl
use warnings;
use strict;
while (<>){
chomp;
if (/a\z/){
print;
}
}
例3:以上面的为例子,将其存储在$1里
#! /usr/bin/perl
use warnings;
use strict;
while(<>){
chomp;
if (/([\d\D]+a\z)/){
print "\$1 contains $1\n";
}
}
例4:接着上题,使用命名捕获
#! /usr/bin/perl
use warnings;
use strict;
while (<>){
chomp;
if (/(?[\d\D]*a\z)/){
print "'word' contains $+{name}\n";
}
}
例5:定位以a结尾,但是再将之后的5个字符捕获至一个独立的内存变量
#! /usr/bin/perl
use warnings;
use strict;
while (<>){
chomp;
if (/(?[\d\D]*a)(?\s[\d\D]{4})/){
print "$+{name1} $+{name2}\n";
}
}
例6:输出以空白结尾的行
#! /usr/bin/perl
use warnings;
use strict;
while (<>){
chomp;
if (/([\d\D]*\s\z)/){
print "$1 m\n";
}
}
1.Perl—正则表达式处理文本
如果m//模式匹配现象成文字处理器的“查找”功能,那么s///替换操作符就是“查找并替换”功能。
2,//; #将结尾的空白替换为空字符串
也可以这么写: s/^\s+|\s+$//g; 去除开头和结尾的空白符
s///也可以采用不同的定界符,但是如果是有左右之分的话,就必须成对使用。比如s{fred}{barney}
同时我们也可以使用之前提到的修饰符,顺序无限后,比如/i,/x,/s
下面是正则表达式中的一些常用模式。
/pattern/ | 结果 | ||
---|---|---|---|
. | 匹配除换行符以外的所有字符 | ||
x? | 匹配 0 次或一次 x 字符串 | ||
x* | 匹配 0 次或多次 x 字符串,但匹配可能的最少次数 | ||
x+ | 匹配 1 次或多次 x 字符串,但匹配可能的最少次数 | ||
.* | 匹配 0 次或一次的任何字符 | ||
.+ | 匹配 1 次或多次的任何字符 | ||
{m} | 匹配刚好是 m 个 的指定字符串 | ||
{m,n} | 匹配在 m个 以上 n个 以下的指定字符串 | ||
{m,} | 匹配 m个 以上 的指定字符串 | ||
[] | 匹配符合 [] 内的字符 | ||
[^] | 匹配不符合 [] 内的字符 | ||
[0-9] | 匹配所有数字字符 | ||
[a-z] | 匹配所有小写字母字符 | ||
[^0-9] | 匹配所有非数字字符 | ||
[^a-z] | 匹配所有非小写字母字符 | ||
^ | 匹配字符开头的字符 | ||
$ | 匹配字符结尾的字符 | ||
\d | 匹配一个数字的字符,和 [0-9] 语法一样 | ||
\d+ | 匹配多个数字字符串,和 [0-9]+ 语法一样 | ||
\D | 非数字,其他同 \d | ||
\D+ | 非数字,其他同 \d+ | ||
\w | 英文字母或数字的字符串,和 [a-zA-Z0-9] 语法一样 | ||
\w+ | 和 [a-zA-Z0-9]+ 语法一样 | ||
\W | 非英文字母或数字的字符串,和 [^a-zA-Z0-9] 语法一样 | ||
\W+ | 和 [^a-zA-Z0-9]+ 语法一样 | ||
\s | 空格,和 [\n\t\r\f] 语法一样 | ||
\s+ | 和 [\n\t\r\f]+ 一样 | ||
\S | 非空格,和 [^\n\t\r\f] 语法一样 | ||
\S+ | 和 [^\n\t\r\f]+ 语法一样 | ||
\b | 匹配以英文字母,数字为边界的字符串 | ||
\B | 匹配不以英文字母,数值为边界的字符串 | ||
a\ | b\ | c | 匹配符合a字符 或是b字符 或是c字符的字符串 |
abc | 匹配含有 abc 的字符串 | ||
(pattern) | () 这个符号会记住所找寻到的字符串,是一个很实用的语法。第一个 () 内所找到的字符串变成 $1 这个变量或是 \1 变量,第二个 () 内所找到的字符串变成 $2 这个变量或是 \2 变量,以此类推下去。 | ||
/pattern/i | i 这个参数表示忽略英文大小写,也就是在匹配字符串的时候,不考虑英文的大小写问题。 | ||
\ | 如果要在 pattern 模式中找寻一个特殊字符,如 “*”,则要在这个字符前加上 \ 符号,这样才会让特殊字符失效 |
下面给出一些例子:
| 范例 | 说明 |
| — | — |
|/perl/ | 找到含有 perl 的字符串|
|/^perl/ |找到开头是 perl 的字符串|
|/perl$/ |找到结尾是 perl 的字符串|
|/c|g|i/ |找到含有 c 或 g 或 i 的字符串|
|/cg{2,4}i/ |找到 c 后面跟着 2个到 4个 g ,再跟着 i 的字符串|
|/cg{2,}i/ |找到 c 后面跟着 2个以上 g ,再跟着 i 的字符串|
|/cg{2}i/ |找到 c 后面跟着 2个 g,再跟着 i 的字符串|
|/cgi/ |找到 c 后面跟着 0个或多个 g ,再跟着 i 的字符串,如同/cg{0,1}i/|
|/cg+i/ |找到 c 后面跟着一个以上 g,再跟着 i 的字符串,如同/cg{1,}i/|
|/cg?i/ |找到 c 后面跟着 0个或是 1个 g ,再跟着 i 的字符串,如同/cg{0,1}i/|
|/c.i/ |找到 c 后面跟着一个任意字符,再跟着 i 的字符串|
|/c..i/ |找到 c 后面跟着二个任意字符,再跟着 i 的字符串|
|/[cgi]/ |找到符合有这三个字符任意一个的字符串|
|/[^cgi]/ |找到没有这三个字符中任意一个的字符串|
|/\d/ |找寻符合数字的字符,可以使用/\d+/来表示一个或是多个数字组成的字符串|
|/\D/ |找寻符合不是数字的字符,可以使用/\D+/来表示一个或是更多个非数字组成的字符串|
|/\/ |找寻符合 这个字符,因为 在常规表达式中有它的特殊意思,所以要在这个特殊符号前加上 \ 符号,这样才会让这个特殊字符失效|
/abc/i |找寻符合 abc 的字符串而且不考虑这些字符串的大小写
无损替换
(my original)=^s/\d+ribs?/10 ribs/;
也可以在修饰符r的作用下这么使用
use 5014;
my original=^s/\d+ribs?/10 ribs/r;
大小写的转换:
\U 将其后的所有字符转换成大写
\L 将后面的所有字符转换成小写
\E 关闭大小写的功能
\l \u 小写的形式仅仅影响后面跟的第一个字符
\u\L 表示首字母大写,后面的字符全部小写,顺序无先后
例子: s/(\w+) with (\w+)/\U$2\E with 2大写,其后的不变。
split操作符
根据模式来拆分字符串;
my @fields =split /separator/,_;
join函数
它的功能和split相反,它可以把这些片段连接成一个字符串
my $result= join $glue,@pieces;
例如 my $x=join “:”,4,6,8,10,12; # $x为“4:6:8:10:12”
在列表上下文中使用模式匹配操作符(m//)时,如果匹配成功,那么返回的是所有捕获变量的列表;如果匹配失败,则返回的是空列表
my $data ="Barney Rubble Fred Flintstone Wilma Flintstone"
my @words=($data=~/(\w+)\s+(\w+)/g);
my $words=($data=~/(\w+)\s+(\w+)/g);
你看 ,这样就可以将标量变成数组或哈希了。
I thought you said Fred and Velma,notWilma
可以这样来 s#(.*?)#$1#g; 如果不加问号的话,就只有一个结果,加了以后才能有两个
把整个文件读进一个变量,然后把文件名作为每一行的前缀。
open FILE,$filename
or die "Can't open '$filename':$!";
my $lines=join '',;
$LINES=~s/^/$filename:/gm;
从命令行直接编辑
在终端中输入 :$perl -p -i.bak -w -e 's/RANDALL/RANDAL/g' fred*.dat
这个就相当于:
#! /usr/bin/perl -w
$^I=".bak";
while(<>){
s/RANDALL/RANDAL/g;
print;
}
-p让perl自动生成一段小程序, -i相当于$^I设为.bak,如果不想备份文件的话,可以直接写-i;-w警告功能;-e后面跟着的是可执行的程序代码
例1:匹配3个$what
#! /usr/bin/perl
use warnings;
use strict;
my $what='fred|barney';
while (<>){
chomp;
if (/($what){3}/){
print "$_\n";
}
}
例2:将Fred换成Larry,同时输出文件名为*.out
#! /usr/bin/perl
use warnings;
use strict;
while(<>){
chomp;
s/Fred/Larry/ig;
print "$_\n";
}
根据上面的程序即可,同时在使用的时候 : perl 程序名 <文件名> 生成的文件名.out
当然也可以指定输出,但是我觉得太麻烦了,就算了吧
例3:将Fred和Barney互换
#! /usr/bin/perl
use warnings;
use strict;
while(<>){
chomp;
s/Fred/Larry/ig;
s/barney/Fred/ig;
s/Larry/Barney/ig;
print "$_\n";
}
例4:在开始前加文本申明:
#! /usr/bin/perl use warnings; use strict; $^I=".bak"; while(<>){ s/\A\#/## Copyright (C) 2013 by Sam \n\#/; print; }
欢迎关注oddxix
有趣的灵魂等着你~
感谢关注
如果觉得写的不错记得点个赞哦~
若有更好的建议欢迎后台指出
以上是关于perl编程综合小骆驼学习笔记的主要内容,如果未能解决你的问题,请参考以下文章