歡迎關注公眾號: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 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";
}
}
10.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) | () 這個符號會記住所找尋到的字符串,是一個很實用的語法。第一個 () 內所找到的字符串變成 |
/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 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+)/\U1/i; 這個例子中僅僅對$2大寫,其后的不變。
split操作符
根據模式來拆分字符串;
my @fields =split /separator/,_;
join函數
它的功能和split相反,它可以把這些片段連接成一個字符串
my glue,@pieces;
例如 my 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
有趣的靈魂等著你~
如果覺得寫的不錯記得點個贊哦~