歡迎來到Linux教程網
Linux教程網
Linux教程網
Linux教程網
您现在的位置: Linux教程網 >> UnixLinux >  >> Linux編程 >> PERL編程

功能豐富的Perl: Perl6語法和正則表達式

  Perl 6 終於即將面世。在本文中,Ted 將向您介紹 Perl 6 語言的語法和正則表達式,並將它們與當前可用的 Perl 5 Parse::RecDescent 模塊進行對比。認識 Perl 正則表達式的新特性,並學會如何具體使用新奇而又功能強大的 Perl 腳本語言。    對所有 Perl 編程人員而言,Perl 6 項目是一個熱門話題。Perl 一直是一門不斷發展的語言,幾乎從任何可以想像得到的角度都可以確定,Perl 6 確實是由 Perl 5 進化而來(不過,您也可以說它們的起源相同)。Perl 6 將運行於 Parrot 之上,Parrot 是一種通用虛擬機,不但可以加載和解釋 Perl 6 字節碼,還可以加載和解釋其他許多語言。    不要讓將來的問題困擾著您。如果您曾經用了幾個月的時間來觀察某個建築物的建築過程,您就會知道,選好地基後要進行挖掘,金屬骨架似乎總是矗立著。工人們來來往往,工作一直在進行,但是表面看到的卻總是陳舊的、丑陋的、生銹的金屬。然後,若干天以後,突然間,建築物就完成了。Perl 6 項目當前正是處於那個長期的中間階段,表面看到的只是生銹的金屬,而工人們正在深入地下進行幕後工作。如果您想洞悉項目的進展,那麼可以去查看最新的 Parrot 發行版本以及 Perl 6 每周的更新(請參閱參考資料中的鏈接)。    本文將向您介紹 Perl 6 語言的語法和正則表達式,並將這些與當前可用的 Perl 5 Parse::RecDescent 模塊進行對比。如果以前對 Perl 5 有所了解,熟悉 Parse::RecDescent,並且有詞法分析(lexing)和句法分析(parsing)方面的經驗,那麼這些會對您掌握本文有很大幫助,此外,本文是為那些對 Perl 6 語法和正則表達式感興趣的所有 Perl 編程人員撰寫的。    Perl 6 正則表達式和語法概述  首先需要聲明一件事:Perl 將通過使用 :p5 修飾符來支持 Perl 5 正則表達式。對於那些對 Perl 6 正則表達式不感興趣或者不想轉到這方面來的人而言,這是一個福音。此外,Perl 6 正則表達式可能(但不是必須)與 Perl 5 中對應的正則表達式有本質上的區別。    在需要時,Perl 6 正則表達式可以被復用。在匹配單一的詞時,復用正則表達式是很荒謬的;但在解析配置文件時,幾乎必須要復用正則表達式(這取決於配置文法的復雜度、發生修改的頻率等)。    在 Perl 5 中,RegeXP::Common 模塊(請參閱參考資料)已經在嘗試復用正則表達式,但是,因為 Perl 5 不允許復用正則表達式,所以不得不將它們封裝在一個模塊接口中。 Perl 6 完全支持這種復用。    盡管您可以編寫類似 Perl 5 正則表達式的模糊而晦澀的 Perl 6 正則表達式,但在默認情況下,允許啟用空格注解;所以,雖然在 Perl 5 中您可以用“hello there”本身來匹配“hello there”,但在 Perl 6 中,您必須將其改為 /hello <sp> there/。這樣就可以在正則表達中將條件清晰地分離開來。    更重要的是,在語法(grammars)內部使用正則表達式時,Perl 6 正則表達式必須不那麼晦澀。編程人員會發現(我希望如此, Larry Wall 也是),對清單 2 的理解與維護要比對清單 1 的容易得多:    清單 1. 沒有語法的正則表達式    # note this is just a language example, not an accurate name matcher  # Perl 6 <[A-Z]> is equivalent to the Perl 5 [A-Z]  # Perl 6 :w modifier surrounds all tokens with "automagic" whitespace,  # which basically means it will match what most people would call  # "Words"  $name = m:w/ <[A-Z]><[a-z]>+ <[A-Z]><[a-z]>+ /;    清單 2. 在語法中作為規則的正則表達式    # note this is just a language example, not an accurate name matcher  grammar English  {  rule name :w { <singlename> <singlename> };  rule singlename { <[A-Z]><[a-z]>+ };  };    清單 2 不僅更容易讀懂,而且維護起來也更容易。例如,Perl 6 本身已經定義了 <upper> 和 <lower> 規則,這使事情變得更為簡單:    清單 3. 在語法中作為規則的經過改進的正則表達式    # note this is just a language example, not an accurate name matcher  grammar Names  {  rule name :w { <singlename> <singlename> };  rule singlename { <upper><lower>+ };  };    瞧!使用 <upper> 和 <lower> 之後,我們就復用了代碼。此外,我們現在還可以處理 Unicode 名稱,而這之前,我們只能局限於處理從 A 到 Z 開頭的名稱。代碼復用是一項出色的技術。    在進行更進一步的維護時,幾乎總是需要對名稱中的破折號或其他名稱(比如 Don Quixote de la Mancha)進行修正(舉例來說)。同樣,在將對個別規則的更改隔離出來,或者在需要時創建一個新規則的時候,您會注意到這是多麼簡單。    語法(Grammars) 是相當簡單的概念。它們是具有專用名稱空間(namespace)和專用子例程的程序包;每一個子例程被稱為一個規則。語法可以繼承其他語法。這樣就使得編程人員既可以復用其他人的代碼,也可以編寫能夠復用的代碼。從 Perl 模塊的 CPAN 存檔文件(archive)獲得的成功中可以明顯地看出這種復用的價值。Perl 6 語法在規則中使用正則表達式,然後可以將這些規則用於其他規則之中。    對比 Parse::RecDescent 與 Perl 6 的語法  熟悉 Parse::RecDescent 的人都知道,它是一個功能強大的工具。Parse::RecDescent 是一個 Perl 5 模塊,只使用很少代碼就可以生成非常強大的語法。這些語法與 Perl 6 的語法是否非常相似呢?是這樣的,Parse::RecDescent 的作者 Damian Conway 深入參與了 Perl 6 的許多工作。因此,很多在 Parse::RecDescent 中證明好用的思想都被應用到 Perl 6 中也就不足為奇了。它們的一些語法有很多類似之處。    Parse::RecDescent(此後稱之為 P::RD)使用 new() 模塊文法來創建新的語法。每個 P::RD 語法成為 P::RD 類中的一個對象,語法中的每一個規則都可以作為用來執行動作的方法。P::RD 語法可以將動作(action)與每一個規則關聯起來,將其作為解析過程中的一個完整部分。在 Perl 5 本身中,解析是一個事件,而使用了擴展語法的動作則是達成目標途徑中的不幸犧牲品(roadkill),那些擴展的語法被證明是造成迷惑的罪魁禍首。這一區別使得 P::RD 比 Perl 5 正則表達式更為有效,原因在於當檢測到匹配對象時,它會使某些事情發生。    Perl 6 語法吸取了 P::RD 的經驗,它意識到了這些動作的實用性,現在,這些動作已經成為其首要的組成部分。每發現一個匹配對象,就會執行一個動作(代碼塊)。即使匹配對象的內容可能已經被修改也是如此!此外,這些動作的語法與 P::RD 中的語法同樣簡單。    清單 4. 包含動作的 Parse::RecDescent 語法  # small extract from my cfperl.pl program's global parser    my $parse_global = new Parse::RecDescent (q{  input: blank comment class section    comment: /^\s*/ '#' { 1; }  blank: /^\s*$/ { 1; }    section: /\w+/ ':'  { $::current_section = $item[1];  $::current_classes = 'any'; 1;  }    class: compound_class '::'  { $::current_classes = $item{compound_class}; 1; }    compound_class: /[-!.\w]+/  });    $parse_global->input("TEXT GOES HERE");    上面的語法只有一個規則,即 input,它將匹配 blank、comment、class 或者 section 規則。這些規則中的每一個規則都有一個定義,它們可以是獨立的或是基於另一個規則的,也可以同時具備這兩種特性。    注意像普通的代碼塊那樣封裝在大括號 { } 內的動作。對於一個片斷(section),動作將全局變量 $current_section 設置為正在進行匹配的片斷,並重新設置 $current_classes 全局變量。對於類,動作將全局的 $current_classes 變量設置為匹配的條目。    這個語法在 Perl 6 中會是什麼樣的呢?    清單 5. 清單 4 語法的 Perl 6 譯本  # this may be buggy - it's certainly untested  # every input is known to be one line, without newline characters  grammar Global  {  rule input { <blank> <comment> <class> <section> }    rule blank { ^^ \s* $$ }    rule comment { ^^ \s* \# }    rule section  { (\w+) \s* \:  {  $::current_section = $1;  $::current_classes = 'any';  }  }    rule class { (<compound_class>) \s* \:\:  {  $::current_classes = $1;  }  }    rule compound_class { <[-!.\w]>+ }  }    Perl 5 的正則表達式  如果您對 Perl 5 正則表達式非常熟悉,那麼可以跳過這一節。    所有 Perl 5 編程人員都熟悉 Perl 5 正則表達式。在進行匹配時,要用 m// 操作符來標識這些正則表達式(有時是可選的),而當匹配並替換時,則要用 s/// 操作符來標識它們。在特定的情況下,/ 字符可以由其他字符取代,並且有一些特定的操作符,它們與正則表達式有幾分類似,不過這樣的操作符不多(例如 tr///)。Perl 5 正則表達式要指明的或者是“尋找此內容”,或者是“尋找此內容,並




Copyright © Linux教程網 All Rights Reserved