[精讚] [會員登入]
5329

[PERL] 14-進階比對 #1--取回比對內容

perl的正規表達式進階比對

分享此文連結 //n.sfs.tw/11715

分享連結 [PERL] 14-進階比對 #1--取回比對內容@新精讚
(文章歡迎轉載,務必尊重版權註明連結來源)
2019-10-25 14:07:12 最後編修
2017-08-27 10:02:23 By 張○○
 

自動目錄

04-基本比對中有提過了基本的比對,此篇更深入一點。

取回比對的內容

如果想取得比對的結果,使用小括號 '()',取回符合的內容用 $1, $2, $3, ...:

舉例而言,如果我們想要取回 email 中的@前面的username和@後面的domain name:

$email = "server\@n.sfs.tw";
$email =~ /([^@]+)\@(.+)/;
print $1; # server
print $2; # n.sfs.tw
print $&; # server@n.sfs.tw

  $email 是被比對的變數,注意這裡的@前面有一個脫逸字元'\',是因為@在雙引號字串中會被當成陣列,所以一定要加上,如果是單引號字串 就不必加。
  =~ 符合比對運算子
  /([^@]+)\@(.+)/ 比對的樣式說明如下
   () 小括號中的內容是要取出符合的內容
     [] 中括號是符合其中字元的集合
       ^@ 在中括號一開始加上這個符號代表是「否定」的意思,全部的意思是只要不是 '@'都行
       + 代表出現1個以上
      \@ 因為在樣式裡面也是能放變數,所以前面加上脫逸字元'\'來確保要比對的是符號'@',如果沒加'\',PERL會判斷這個陣列變數是否存在,有存在就會置換成該變數;不存在時就當成是一般字元處理,有時也許會造成錯誤。
   () 小括號中的內容是要取出第二個符合的內容
     . 代表任一個字元
       + 代表出現1個以上 

因此如果$email符合比對的樣式,第3行和第4行用特殊變數 $+數字依序取回符合的內容。

PERL用 $1, $2, $3, $4....是以小括號的左邊出現次序,依序取回符合的內容。
$& 代表比對成功的部分,這是PERL的特殊變數。

另外,
$` 代表比對到的字串之前半段所有字串
$' 代表比對到的字串之後半段所有字串

 例如我們取出IP中每個字節的數字

$ip='211.75.194.243:8080';
$ip=~ /((\d+)\.(\d+)\.(\d+)\.(\d+)):(\d+)/;

print "$1, $2, $3, $4, $5, $6\n"; # 211.75.194.243, 211, 75, 194, 243, 8080

可以看到 $1是第一個左括號的範圍。

上面的程式要做一點調整,因為有時比對不成功的話 $1 = $2 = $3 = ... = '' 會是空字串,必須加上判斷

$ip='AAA.75.194.243:8080';
if($ip=~ /((\d+)\.(\d+)\.(\d+)\.(\d+)):(\d+)/){
  print "$1, $2, $3, $4, $5, $6\n";
}else{
  print "比對失敗\n";
}

這樣就能做錯誤控制。

取回比對的內容同時也加入比對

有時我們需要把比對成功的字串同時再比對,例如要找出有連續字元的單字,例如 look, snoop, peer, employee 符合條件。

這時就需要用到特殊變數 \1, \2, \3, ...,和$1, $2, $3不同的地方在於它們只能放在樣式之中,來看看範例。

@words= qw ( usually positive floor flee eels country );

foreach(@words){
  if( $_ =~ /([a-z])\1/ ){
    print $_. "\n";
  }
}

第4行 利用\1將第一個比對符合的小括號再次比對,來檢查重覆出現的字元。

結果

usually
floor
flee
eels

整篇文章中的文字搜索

上面學到了怎麼取出具有重覆字元的單字,如果是整篇文章要取資料。來看範例:

$doc=<<"DOC";
       If  FIRST or INCREMENT is omitted, it defaults to 1.  That is, an omitted INCREMENT defaults to 1 even when LAST is smaller than
       FIRST.  The sequence of numbers ends when the sum of the current number and INCREMENT would become greater  than  LAST.   FIRST,
       INCREMENT,  and LAST are interpreted as floating point values.  INCREMENT is usually positive if FIRST is smaller than LAST, and
       INCREMENT is usually negative if FIRST is greater than LAST.  FORMAT must be suitable for printing one argument  of  type  'dou‐
       ble';  it defaults to %.PRECf if FIRST, INCREMENT, and LAST are all fixed point decimal numbers with maximum precision PREC, and
       to %g otherwise.

       GNU coreutils online help: <http://www.gnu.org/software/coreutils/>  Report  seq  translation  bugs  to  <http://translationpro‐
       ject.org/team/>
DOC

while($doc =~ /[\w]*([\w])\1[\w]*/g){
  print $&. "\n";
}

第1行 $doc只是一篇文章
第13行 樣式是 /[\w]*([\w])\1[\w]*/g 說明如下

  [\w]* \w代表[a-zA-Z_0-9]這些字元,有出現0個字元以上,當出現0個時,重覆字元會在單字面出現。
   () 小括號中的內容是要取出符合的內容
      [\w]+ 小號內代表有1個字元以上
   \1 當第1個小括號比對符合時,再拿來比對,表示連續出現的字元
  [\w]*代表\w出現0個字元以上,當出現0個時,重覆字元會在單字面出現。

第14行是印出全部比對的範圍。

在樣式的最後面有一個字元 'g' ,這並不是打錯,而是稱之為「修飾子」的字元,這算是一個比對位置指標,下次的比對會從上一次比對符合的目標下一個字元找起。千萬不能省略這個g,省略的話會掉入無窮迴圈中。有關於更多修飾子的內容會在下一篇說明。

結果

omitted
omitted
smaller
current
usually
smaller
usually
all
http
www
http

有人會問,如果把第13行改成

while($doc =~ /([\w])\1/g){

不就剛好能找出兩個連續的字元了嗎,為什麼還有多旁邊的 [\w]* ,理由很簡單,因為那樣的輸出結果會是:

tt
tt
ll
rr
ll
ll
ll
ll
tt
ww
tt

你不會知道那是什麼字。

上一篇 13- 變數的視界
回到目錄 01-撰寫第一隻PERL程式
下一篇 15-進階比對 #2--使用更多修飾子

END

你可能感興趣的文章

[PERL] 取得字串長度 使用length來取得字串長度

[PERL] 中文字字串拆解,把中文字串逐字拆開 中文字字串拆解是門學問

自行撰寫syslog server建立資訊安全控管中心#4 -- 過濾條件設定 利用PERL將syslog收攏到資料庫的程式,過濾條件設定

[PERL] 04-基本比對 perl的正規表達示基本比對

Freebsd11上安裝PERL模組 freebsd11+ perl module 在freebsd上安裝module還算簡單

[PERL] 06-運算子 #2 PERL的運算子介紹,總共有21種

我有話要說

>>

限制:留言最高字數1000字。 限制:未登入訪客,每則留言間隔需超過10分鐘,每日最多5則留言。

訪客留言

[無留言]

隨機好文

好用的3+2碼郵遞區號查詢系統推薦 網路上找到用地址輸入判斷3+2碼郵遞區號的辨識率不高,除了這個網站…

正則表達式:Email名稱防止連續輸入點(.)及下底線(_) Email的名稱中要允許特殊符號,但又不允許連續出現的正則表達式

[CKeditor4] 修改調色盤 修改ckeditor預設的調色盤

[ilo3] dl380 g7 ILO3 &更新韌體 HP DL380 g7 ILO3 更新ilo3 firmware

[Freebsd] 建立ramdisk Freebsd 建立ramdisk,作為高速的暫存空間