【JavaScript】正則表達式刪除代碼註釋
約定:本文中,以數字內容表示代碼正文,其餘字符內容表示註釋內容。
代碼註釋有三種形式:
第一種:
|
|
第二種:
|
|
第三種:
|
|
其實第二種和第三種是同一類型。
代碼實現與運行效果
直接給代碼,看運行效果,然後再來講正則表達式爲什麼要這麼寫.
代碼實現如下:
|
|
控制檯輸出如下:
單行註釋 //
的處理
代碼的每一行中,雙斜杆//
及其後內容,不管是任何字符,都是註釋。
所以,只是正規表達式挑出以//
開始,後續不論任何字符都直接可以刪除。
所以具體的表達如下:
|
|
開頭的//
表示遇到//
就開始匹配,.
表示//
後可匹配的字符內容爲除了換行符以外的任意一個字符,*
表示//
後面符合條件的字符出現次數可以爲0或任意次數。
考慮到//
在JavaScript中需要轉義,所以在定義時轉義後的表達式如下:
|
|
使用該表達式匹配代碼,會發現只有第一次出現的的註釋會被刪除,第二個及以後的註釋都還在。好吧…需要再添加全局匹配功能,即添加g
。代碼如下:
|
|
這樣,不論代碼中出現多少行 //
註釋,都可以被一一匹配出現替換掉了。
多行註釋 /* */
的處理
/* */
的特殊之處在於它可以單行註釋,也可以多行註釋,所以比//
要多過濾掉換行符,所以在//
中的.
只代表非換行符的其它所有字符,所以.
就不能用了。
看看正規表達式語法規範中,可以用\s
和\S
的合集來表示所有的字符。
字符 | 含義 |
---|---|
\s | 匹配任何空白字符,包括空格、製表符、換頁符等等。等價於[ \f\n\r\t\v]。 |
\S | 匹配任何非空白字符。等價於[^ \f\n\r\t\v]。 |
合集的表示用[]
將\s\S
包含在內即可。所以改進一下,初始的表達式如下:
|
|
即以/*
開始,以*/
結尾,中間的任意字符的組合都符合匹配規則。當然,/*
及*/
在上面的表達式中都用轉義字符\
轉義了。
但上面的表達式還有問題。當遇到如下的代碼,
|
|
匹配的結束字符串*/
有兩個,那麼每次匹配時,該告訴解釋器以該選擇哪個呢?
這就涉及到正規表達式的貪婪模式與非貪婪模式。
貪婪模式即儘可能的去匹配更多符合條件的字符內容,在上面的例子中,即匹配到*/ 456
才結束,運算之後的結果將會是:123456 456
。
非貪婪模式即匹配儘可能少的字符內容,在上面的例子中以匹配到*/ 123
結束,運算的結果將會是123456 123 456
。
很明顯,這種場景下我們需要的是非貪婪模式。
再次查詢正規表達式語法規範,可以用?
來使用非貪婪模式,所以最後的改進代碼如下:
|
|
整合
當然,我們也可以通過 |
串接起兩個匹配規則。相當於’或‘運算。串接後的正規表達示如下:
|
|
單行註釋要排除 http://
等
在使用過程中,發現上文中的單行註釋會把 http://
或 ftp://
等字符串定義一併當做註釋處理掉了。
下面給出帶http://
的干擾項的源字符串,及當前過濾出的錯誤結果及期待的正確結果。
|
|
很可惜,JavaScript並不支持正則表達式中的反向否定預查,那隻好再想想辦法。
查看JavaScript文檔,發現String.prototype.replace(regexp|substr, newSubStr|function)的第二個參數是支持函數的。即目標替換符可以通過函數來按自定義的邏輯來決定,這也意味着替換規則是靈活可變的。
根據文檔,傳入的函數定義如下:
Possible name | Supplied value |
---|---|
match | The matched substring. (Corresponds to $& above.) |
p1, p2, … | The nth parenthesized submatch string, provided the first argument to replace() was a RegExp object. (Corresponds to $1, $2, etc. above.) For example, if /(\a+)(\b+)/, was given, p1 is the match for \a+, and p2 for \b+. |
offset | The offset of the matched substring within the whole string being examined. (For example, if the whole string was ‘abcd’, and the matched substring was ‘bc’, then this argument will be 1.) |
string | The whole string being examined. |
那麼通過該函數可以得到//
開始的字符串match
,由於在match
中可能存在多個//
,我們需要找到在match
中第一個前綴不爲:
的//
位置,從該位置開始的內容皆爲代碼註釋。
優化後的deleteCodeComments()函數具體的實現和邏輯說明見如下代碼:
|
|
運行效果如下圖: