天天看點

《重構HTML:改善Web應用的設計(修訂版)》——2.4 正規表達式

本節書摘來自異步社群《重構html:改善web應用的設計(修訂版)》一書中的第2章,第2.4節,作者: 【美】elliotte rusty harold 更多章節内容可以通路雲栖社群“異步社群”公衆号檢視。

手工檢查或者改動一個網站的每一個檔案,即使是一個小型網站的少量檔案,也是一件十分乏味和費勁的事情。讓計算機搜尋錯誤,可以的話同時自動修複錯誤,這顯然是更高效的做法。很多工具都支援這種方式,包括諸如grep、egrep和sed等指令行工具,諸如jedit、bbedit、textpad和pspad等文本編輯器,當然也包括諸如java、perl和php等程式設計語言。所有這些工具都提供了一門專門的搜尋文法規則,被稱為正規表達式。盡管在不同的工具中它的表現略有不同,但基本文法幾乎是一緻的。

為達到說明的目的,本節中我将使用jedit文本編輯器作為搜尋和替換工具。選擇它的原因在于它提供非常多适合你的特性,gui也非常合理,而且還是開源的。由于它是用java編寫的,是以本質上說能夠運作于任何平台上。

然而,這裡我展示的技術當然不會隻局限于一個編輯器上。我在工作中常用到的是界面稍為優美的bbedit,但它隻能運作在mac上。當然還有很多其他的選擇,如果你喜歡某一種工具,那就用它吧。其實你需要的是:

完整支援正規表達式的搜尋和替換;

遞歸搜尋目錄的能力;

過濾搜尋檔案的能力;

能夠顯示變更且不需手工去驗證的工具;

自動識别不同的字元編碼和行尾結束慣例(line-ending conventions)。

滿足上述條件的工具應該就夠用了。

2.4.1 搜尋

正規表達式的第一個目的是查找所有可能是錯誤的東西。比如,最近我發現在一個檔案中,我老是把2006拼錯為20066,而且這個錯誤可能不止一處,是以我需要通過搜尋該字元串來檢查這個錯誤。

在jedit中,你可以使用directory菜單中的search/search執行一個多檔案搜尋。選中這個菜單項後出現了如圖2-6所示的對話框,圖中示例有所調整。

《重構HTML:改善Web應用的設計(修訂版)》——2.4 正規表達式

需要搜尋的字元串(即目标字元串)在第一個輸入框中。

用于替換目标字元串的字元串在第二個輸入框中。這裡我隻查找而不替換,是以不用輸入替換字元串。

directory單選按鈕表示是否搜尋多檔案。你可以隻在目前檔案甚至是目前選中的文本中進行搜尋。

将filter設定為.html表示搜尋隻以.html為字尾的檔案。你可以修改此處以搜尋不同類型或不同部分的檔案。比如,我常常隻需搜尋那些被命名為news2000.html、news2001.html、news2002.html等舊資訊檔案。在這種情況下,我需要把filter設定為news2.html。當然我也可以通過重寫過濾器的正規表達式,比如newsdddd.html,搜尋到包括news1999.html等更舊的檔案。

我還指定了需要搜尋檔案所在的本地目錄,本例中是/users/elharo/cafe au lait/javafaq。

選中search subdirectories複選框,否則,jedit不會搜尋javafaq的下一層目錄,而隻是javafaq這一層。

選中keep dialog複選框,這在搜尋完成後還能保持對話框的打開狀态。

選中ignore case複選框,這允許正規表達式忽略字母大小寫。對你來說,- 大部分情況下都是要忽略大小寫的。

選中regular expressions複選框,如果你隻是查找一個常量字元串,就沒有必要選中此項。但是,大部分的搜尋都會比單純的字元串搜尋複雜。

選中hypersearch,這會出現一個顯示所有比對結果的視窗,而不隻是下一項的比對結果。

幸好這個特定的問題看起來已經解決掉了,但我還發現了另一個更嚴重的問題。由于一些未知因素,我在其中一個網站中的連結中使用了雙等号,如下所示:

是以,連結無論在哪兒都是失效的。第一步是要找出涉及此問題的所有檔案。在這個例子裡,錯誤的字元串是常量,并且在正确的文本中出現的可能性也很小,是以非常容易進行搜尋。圖2-7的hypersearch結果顯示,這個問題在476個檔案中出現了4475次。

《重構HTML:改善Web應用的設計(修訂版)》——2.4 正規表達式

在錯誤不多的情況下,你隻用單擊每個錯誤以打開檔案,并手工修複就行了。有時這也是必需的,甚至是最簡單的解決方案。但是在錯誤量成千上萬時,你就有必要使用工具來修複了。在上面的例子中,解決方法是不言自明的:在replace with文本框中輸入href=,再單擊replace all按鈕就行了。

執行此類操作時必須十分小心,否則小錯也會釀成大禍。錯誤的搜尋和替換可能是錯誤問題的根源。在執行整站的操作之前,你應該先在少量的檔案上進行搜尋和替換,對你的正規表達式測試一番。

更重要的是務必在網站的備份副本上進行操作,在每次更改後務必運作測試套件,并在檔案被改動的情況下當場核對,以保證正确性。如果發生了某些錯誤,編輯器的撤銷功能将會非常有用。但并不是所有的編輯器都能有一個足夠大的緩沖區(buffer)支援多重撤銷,是以處理不了上千次的改動。假如編輯器不支援多重撤銷,馬上删除正在編輯的副本并用一個原始的副本進行替換,以防止搜尋出錯。跟其他複雜的代碼一樣,有時你不得不多花點時間對正規表達式進行排錯。

2.4.2 搜尋模式

通常你不關心搜尋的具體内容,但必須了解它的通用模式。舉例來說,要查找剛過去的幾年的公元表示法,實際上是要搜尋以200開頭的四位數字。查找name=value這種形式的屬性對時,并不能保證是name=value、name='value'還是name="value"格式。搜尋所有不管是否有屬性的

起始标簽。這些都是使用正規表達式的絕佳場合。

在正規表達式中,特定的字元和模式可以表示其他的字元集合。比如,d表示任意的數字。是以要搜尋2000年到2009年中的任意一年,可以使用200d這樣的正規表達式,它能比對2000、2001、2002等一直到2009這些年份。

但是200d這個正規表達式也會比對12000、200032、12320056或其他可能不是年份的字元串。(準确地說,它比對符合200d的字元串子串,而不是整個字元串)。是以,你可能希望指明需要比對前後都有空白③的字元串。元字元s比對空白,是以現在我們可以将正規表達式重寫為s200ds,這樣才可以實作隻比對看起來是本世紀頭十年中年份的字元串。

當然這還是不能保證比對到的字元串形式就一定是年份,它也有可能是價格、人數、分數、電影标題等。你需要看一下比對清單,檢查是否是你想要的結果。尤其是在如此簡單的情況下,誤報的情況需要加以注意。當然,更進一步地完善正規表達式可以避免誤報,或者手工删除偶然的比對,都是可行的。

這裡有更多的方法。比如我們在這個搜尋中可以使用b200db。元字元b比對單詞的開頭或結尾,完全不會選中任何字元。這就可以避免需要選中單詞前後的空白,也可以識别在句子末尾的諸如“this is 2008.”中的年份。但是它不能差別是英文句号還是數學中的小數點,是以也會比對到“in 中的2005。

你可以簡單地使用或操作符|來分隔年份,比如:

但單詞分界問題還是避免不了。

有時你得暫時停止使用搜尋。特别是由cms、模闆頁面或者其他程式自動生成的内容時,搜尋隻能用來找錯,定位程式在哪裡産生了錯誤的标記。然後必須改正程式錯誤才能生成正确的标記。在這種情況下,你就不必太擔心誤報了,因為所有的更改都是手工執行的。這種搜尋隻找錯不修錯。

如果你沒有停止使用搜尋,并且繼續替換,這需要謹慎行事。正規表達式比本書中的例子更棘手,涉及html就更不用說有多麼狡猾了。不管怎麼說,對于清理html它都是極有價值的工具。

注解

如果你并沒有太多的正規表達式經驗,請參考附錄a中更多的例子。同時我推薦jeffrey e. f. friedl的mastering regular expressions,3rd edition(o’reilly,2006)。

繼續閱讀