天天看點

正規表達式 - 你必須掌握的

很多人不願意修改公共代碼,因為公共代碼一修改,将可能影響到别的工程代碼,必須同時修改大量的别的工程代碼。對于簡單的修改,比如函數名修改,使用簡單的批量查找替換就可以完成。但如果遇到更加複雜的情況,很多人手足無措,隻能一個一個的手工修改。《卓有成效的程式員》裡有這麼一個故事:

 “事情發生在一個項目中,那個項目已使用了1000個EJB(Enterprise Java Bean),當時決定所有的非EJB方法(就是說除了EJB托管的回調方法之外的所有方法)都需要一個額外的參數。原本估計需要一個人花6天來手工完成。但一個熟悉正規表達式的開發人員,用他信賴的編輯器(Emacs)僅使用兩個小時就完成了所有的替換。也就是那一天開始,我決定好好學習正規表達式。”

可以想象一下,一個原本6天的手工工作量, 最後隻需要兩小時。(1小時58分鐘建立正确的文法,然後不足兩分鐘時間去執行。)

曾有人總結了程式員的七種武器,其中就有“正規表達式”。如果你現在對正規表達式還是一知半解,好好的靜下心來,用心花上2個小時,仔細學習和研讀一下正規表達式文法規則,是絕對值得的。要學習正規表達式,資源非常多。 如果想要系統的學習,建議看《精通正規表達式》等書。如果你想要快速入門,我推薦一下園裡最近很火的Jimmy Zhang曾經寫過的一個簡易教程:

學習資源:

正規表達式工具:

我首推RegexBuddy了。下面這個位址裡有RegexBuddy3.2.1完整版的下載下傳位址(如果你仔細浏覽這個網站,會發現此人是一個正規表達式狂熱分子):

<a href="http://iregex.org/blog/regexbuddy321.html" target="_blank">http://iregex.org/blog/regexbuddy321.html</a>

接下來,我們回到開頭講到的修改公共庫的問題。我來舉一個的例子,我們設計了一個Game類,提供Start執行個體方法如下:

正規表達式 - 你必須掌握的

public class Game

{

    public void Start(int totalTime, string gameName)

    {

        // 

正規表達式 - 你必須掌握的

    }

}

正規表達式 - 你必須掌握的

然後,該方法被大量其他代碼使用。直到某一天,我們決定将Start方法的兩個參數順序對換,因為gameName作為第一個參數看起來更加順眼。。。然後,我們觀察了一些使用到Game類的代碼,發現有非常多的地方使用到了該代碼,但幾乎的代碼都使用了類似如下的方法調用Start方法:

正規表達式 - 你必須掌握的

Game game = new Game();

game.Start(1, "NancyTetris");

Game myGame = new Game();

int totalTime = 10;

string gameName = "NancyGLine";

myGame.Start(totalTime, gameName);

正規表達式 - 你必須掌握的

當然,實際情況下,調用該方法的代碼千奇百怪,對于某些複雜情況,想要通過一個正規表達式達到完美的批量替換确實很難。這裡,我就将問題簡化一下,隻是給大家提供一個思路。我假設所有調用該方法的代碼都使用了如上的方法進行調用。(為了簡化正規表達式,易了解,我假設調用代碼都遵循代碼規範,不會去多出一些多餘的空格,也不胡亂換行。)

那麼,一個怎樣的正規表達式能夠将上面的一段代碼中的Game執行個體的Start方法的兩個參數調換呢?

答案:

搜尋:Game (\w+) = new Game\(\);([\W\w]*?)\1.Start\(([\w\"]+), ([\w\"]+)\);

替換:Game $1 = new Game();$2\1.Start($4, $3);

這個例子很常見,也很有用,如果你還不會,請耐心花上2個小時學習,然後解決它!

在實際的批量搜尋替換過程中,你肯定會遇到各種各樣的麻煩,因為你會發現,調用它的代碼風格千差萬别,比如上面的例子,可能有人将Game執行個體做為一個參數傳遞到了另外一個函數(甚至這個函數在另外一個檔案裡),如:

正規表達式 - 你必須掌握的

public void Do()

    Game game = new Game();

    Foo(game);

// Foo方法可能在另外一個檔案裡

public void Foo(Game game)

    game.Start(1, "NancyTetris");

正規表達式 - 你必須掌握的

甚至,某些人不符合代碼規範的怪異寫法也會讓你非常頭疼。你會發現一個正規表達式已經不能一次性做完所有事情,這時,你也許需要編寫一定的腳本進行更加複雜的處理,假如正規表達式這把武器在你的手上運用自如,你是否會感覺一切都變得那麼簡單呢?如果你有更多實際的正規表達式批量替換的經驗,歡迎分享!

繼續閱讀