[精讚] [會員登入]
1485

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

perl的正規表達式進階比對

此文完整連結 http://n.sfs.tw/11715

複製連結 [PERL] 14-進階比對 #1--取回比對內容@新精讚
(文章歡迎轉載,務必尊重版權註明連結來源)
2018-01-02 22:53:02 最後編修
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--使用更多修飾子

你可能感興趣的文章

Perl 計算經過的時間 Perl 計算程式執行經過的時間

關於Perl,你得知道這幾點 Perl 有不少奇異的地方,值得看一看

Perl 的列舉寫法(map list) 使用列舉的寫法來設定陣列,非常的強大

[PERL] 08-陣列 #2 --操作 更多perl陣列的操作,如拆開、黏合、取出、加入等等

PERL 正規表達式會用到的符號 PERL在比對時常常會用到符號整理

[PERL] 19-模組的安裝和維護 模組的安裝和維護

[PERL] 15-進階比對 #2--使用更多修飾子 perl的正規表達式進階比對

[PERL]] find 和 perl 的結合--大量檔案中文字的取代 利用PERL作大量的文件取代

PERL的真值和假值(布林值) 整理Perl中的判斷真假的結果

[PERL] 13- 變數的視界 Perl 的副程式就是所謂的函數

我有話要說


限制:留言最高字數1000字,超過部分會被截掉。請注意:留言不可帶有網址,會被濾掉。 限制:未登入訪客,每則留言間隔需超過10分鐘,每日最多5則留言。

訪客留言

[無留言]

隨機好文

PHP for sphinx 函式庫安裝 PECL/sphinx PHP>= 5.2.2 已經能原生支援 sphinx,可是預設的沒有裝,我們得自己裝才能用

[札記] 2016.7~12月札記 札記,只是札記

維修冰箱 維修冰箱

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

[PHP] 檢查IP是否在某個網段內 mtachcidr 要檢查IP是否在某個網段內,要寫幾行?10行?5行? 不用,只要2行。以下是我寫的 code /** * matchCI