【perl编程综合】小骆驼学习笔记

欢迎关注公众号:oddxix
最近算是系统的学完了perl了,一下是对小骆驼的整理,感谢博主铁汉柔情1990的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!";

第一行#! /usr/bin/perl的意思是使用/usr/bin目录下的Perl来解读下面的程序,其中#!是一个特殊注释符,一般的#是普通的注释符,从开始到行结尾的部分,普通的注释符是没有啥意义的,就是在程序里面一个简单说明说明,方便其他人来读你的程序的时候更容易理解。 一般perl都是在/usr/bin这个目录下,如果不在记得修改其地址,当然还可以通过#! /usr/bin/envperl来帮你定位perl

这是两个代码,但输出的结果一样。\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 fred,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后可以锚定多行的位置, 比如/^fred/m /fred/m 分别表示锚位与多行的行首和行尾

=~绑定操作符

默认情况下模式匹配的操作对象是_,而绑定操作符则是告诉perl,拿右边的模式来匹配左边的字符串,而不是匹配_
例如: 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";
    }
    }

10.Perl--正则表达式处理文本

如果m//模式匹配现象成文字处理器的“查找”功能,那么s///替换操作符就是“查找并替换”功能。
_="green scaly dinosaur"; s/(\w+)(\w+)/2,1/g; #替换后为“scaly,green dinosaur” 上面的例子中/g为全局替换。我们在缩减空白的时候,可以这么做: s/^s+// ; #将开头的空白替换成空字符串 s/s+//; #将结尾的空白替换为空字符串
也可以这么写: 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 的字符串
/cg*i/ 找到 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 copy =original)=^s/\d+ribs?/10 ribs/;
也可以在修饰符r的作用下这么使用
use 5014;
my copy =original=^s/\d+ribs?/10 ribs/r;

大小写的转换:

\U 将其后的所有字符转换成大写
\L 将后面的所有字符转换成小写
\E 关闭大小写的功能
\l \u 小写的形式仅仅影响后面跟的第一个字符
\u\L 表示首字母大写,后面的字符全部小写,顺序无先后

例子: s/(\w+) with (\w+)/\U2\E with1/i; 这个例子中仅仅对$2大写,其后的不变。

split操作符

根据模式来拆分字符串;
my @fields =split /separator/,string; 期间只要模式在某处匹配成功,该处就是当前字段的结尾,下一个字段的开头。 my @fields =split /:/,"abc:def:g:h"; #得到的是("abc","def","g","h") 如果是两个分隔符在一起,就会产生空字段,保留开头处的空字段,舍弃结尾处的空字段。 my @fields =split #等效于my @fields =split /\s+/,_;

join函数

它的功能和split相反,它可以把这些片段连接成一个字符串
my result= joinglue,@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

有趣的灵魂等着你~

如果觉得写的不错记得点个赞哦~

推荐阅读更多精彩内容

  • 随着年复一年的淡而无味的春节,除了鸡鸭鱼肉等摆满桌,在春晚作为背景音下的大家刷手机的百态表现,海坛特哥在除夕夜告白...
    泳霖律师随笔阅读 65评论 0 0
  • 一两愿你江南多雨带油伞, 二两愿你酷暑可以轻摇扇, 三两愿你无病无忧心常宽, 三两三,余下三。 我在这里,一关接一...
    墨语涵阅读 169评论 3 1
  • 数据科学是什么 数据挖掘、机器学习、人工智能都是数据科学的一个分类。 接下来,我们从这几个方面来剖析一下数据科学 ...
    地主是我爸阅读 163评论 0 1