【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

有趣的靈魂等著你~

如果覺得寫的不錯記得點個贊哦~

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 228,443評論 6 532
  • 序言:濱河連續發生了三起死亡事件,死亡現場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發現死者居然都...
    沈念sama閱讀 98,530評論 3 416
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 176,407評論 0 375
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 62,981評論 1 312
  • 正文 為了忘掉前任,我火速辦了婚禮,結果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當我...
    茶點故事閱讀 71,759評論 6 410
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發上,一...
    開封第一講書人閱讀 55,204評論 1 324
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當著我的面吹牛,可吹牛的內容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,263評論 3 441
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 42,415評論 0 288
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當地人在樹林里發現了一具尸體,經...
    沈念sama閱讀 48,955評論 1 336
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 40,782評論 3 354
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發現自己被綠了。 大學時的朋友給我發了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 42,983評論 1 369
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,528評論 5 359
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質發生泄漏。R本人自食惡果不足惜,卻給世界環境...
    茶點故事閱讀 44,222評論 3 347
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 34,650評論 0 26
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 35,892評論 1 286
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 51,675評論 3 392
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 47,967評論 2 374

推薦閱讀更多精彩內容

  • 隨著年復一年的淡而無味的春節,除了雞鴨魚肉等擺滿桌,在春晚作為背景音下的大家刷手機的百態表現,海壇特哥在除夕夜告白...
    陳律隨筆閱讀 206評論 0 0
  • 一兩愿你江南多雨帶油傘, 二兩愿你酷暑可以輕搖扇, 三兩愿你無病無憂心常寬, 三兩三,余下三。 我在這里,一關接一...
    墨語涵閱讀 261評論 3 1
  • 數據科學是什么 數據挖掘、機器學習、人工智能都是數據科學的一個分類。 接下來,我們從這幾個方面來剖析一下數據科學 ...
    地主是我爸閱讀 304評論 0 1