經常用到EmEditor來編輯純文本文檔。最近接觸了正則表達式,感受到其功能非常強大。
	正則表達式實在包含的內容太多, 僅僅用一篇文章來涵蓋是沒可能的了, 所以我只是簡要的做些介紹和基本的模式應用舉例. 
	正則表達式, 英文 Regular expression, 簡寫Regexes或Regex. 
	
	應用概述: 提供與預期的搜索結果匹配的確切文本來進行字符串的搜索和替換操作, 這種技術不僅僅用于開發領域, 更被集成到一些常見的文本擴展編輯器, 如UltraEdit, Emeditor等. 歷史上第一個實用應用程序是Unix 中的qed 編輯器。 
	
	舉一個簡單的類比: 我們對DOS中的通配符"*"和"?"應該很熟悉, 如命令"dir *.exe" 將列出所有后綴名為exe的文件名. 正則表達式提供的方法與其類似, 而且遠比通配符強大的多. 
	
	從某種意義上說, 正則表達式是一種語言, 通過及其簡短的一行代碼即可以高效, 精確的描述要匹配的復雜文本, 當然, 它最大的優點也是他最大的缺點: 語法復雜, 創建困難. (熟悉之后就可以忽略后半句了 :p) 
	
	主要應用: 
	數據驗證; 這是正則表達式在開發中最常見的應用, 通過測試字符串內的模式。來驗證輸入的字符串是否為郵政編碼, 電話號碼, 電子郵件地址, 信用卡號碼等等。 
	搜索和替換文本; 用正則表達式來搜索文檔中的特定文本塊, 根據需要用其他指定的文本塊進行替換。這也是文本編輯中的一個常見應用, 如將網頁中的HTML代碼轉化為UBB代碼. 
	
	1. 啟用正則表達式 
	菜單: Search - Find (Replace) - 選中 Use Regular Expressions 
	
	2. Emeditor 正則語法 
	正則表達式是普通字符和元字符組合的一種模式. 它的結構與算術表達式的結構類似, 各種元字符和運算符可以將小的表達式組合起來,創建大的表達式。通過在一對分隔符之間放置表達式模式的各種組件,就可以構建正則表達式。 
	
	2.1 普通字符 
	普通字符是指除了 ".", "*", "?", "+", "(", ")", "{", "}", "[", "]", "^", "$" 和 "/" 這些特殊字符之外的所有其他字符. 而這些特殊字符也可以通過前面加上"/"前綴而變為普通字符. 比如, 搜索"CCF"即為在文本中匹配所有的"CCF"字符串, 搜索"/[CCF/]"則是在文本中匹配所有的"[CCF]"字符串. 
	簡而言之, 普通字符即為只匹配自身的字符. 
	2.2 元字符 
	元字符不匹配其自身,它用特殊方式來解析從而實現更多的邏輯功能。正則表達式通過元字符在模式中包含選擇和循環 
	2.2.1 特殊字符 
	
	3. 匹配除換行符 /n 之外的任何單個字符。 
	( ) 分組捕獲(子表達式)的開始和結束。可以捕獲子表達式以供以后使用。 
	[ ] 中括號表達式的開始。 
	中括號表達式是在方括號內包含一個或多個字符構成的列表的表達式。普通字符在中括號內表示本身,大多數特殊字符在中括號表達式內出現時失去它們的意義。除了轉義字符'/', (要包含'/', 需要使用'/') 如: 正則表達式 No [1234] 匹配 No 1, No 2, No 3 和 No4. 如果想在中括號中使用一個范圍作為列表來匹配字符,可以用連字符 '-' 將范圍中的開始字符和結束字符分開。單個字符的字符值確定范圍內的相對順序。如: 正則表達式 No [1-4] = No [1234] 
	注意 1. 開始值的Unicode值必須在結束值Unicode值的前面。 
	注意 2. [/-]匹配連字符'-', 放在中括號列表的開始或結尾也可起到同樣的效果, 如 [-c-f] 匹配 c 至 f 的字符和連字符 
	
	如果需要匹配不屬于列表或范圍內的任何字符,可以在列表開頭加上'^'前綴。如: 正則表達式 No [^1-4] 匹配 No 5 和更大的編號. 
	
	中括號表達式還可進行組合, 如 [A-Za-z0-9] 匹配A-Z, a-z, 0-9 的字符 
	
	/ 將下一字符標記為特殊字符、文本、反向引用或八進制轉義符。例如, 
	字符 n 匹配字符 n 
	/n 匹配換行符 
	序列 / 匹配 / 
	序列 /( 匹配 ( 
	| 替換字符, 對|左右的兩個項分別匹配進行選擇。或者說, 就是邏輯的OR的概念 
	{ } 標記限定符表達式的開始。 
	(數量)限定字符 
	限定字符能夠指定正則表達式的某個部分必須出現的次數 
	* 零次或多次匹配前面的字符或子表達式。如,c*f 可以匹配 f 和 ccf。* = {0,} 
	+ 一次或多次匹配前面的字符或子表達式。如,c+f 可以匹配 cf 和 ccf,但不匹配 f。+ = {1,} 
	? 零次或一次匹配前面的字符或子表達式。如,cc?f 可以匹配 cf 或 ccf。? = {0,1} 
	{n} n 是非負整數。正好匹配 n 次。如,c{2}f 可以匹配 ccf。 
	{n,} n 是非負整數。至少匹配 n 次。如,c{2,}f 不匹配 cf,而可以匹配 ccccccf。c{1,} = c+。c{0,} = c* 
	{n,m} m 和 n 是非負整數,其中 n <= m。至少匹配 n 次,至多匹配 m 次。如,c{1,3} 可以匹配 ccf 中的cc。c{0,1} 等效于 c?。 
	
	2.2.2 控制字符 
	/a Bell 字符。= 0x07 
	/f 換頁符匹配。= 0x0C 
	/n 換行符匹配。= 0x0A 
	/r 匹配一個回車符。= 0x0D 
	/t 制表符匹配。= 0x09 
	/v 垂直制表符匹配。= 0x0B 
	/e ASCII 換碼字符。= 0x1B 
	{post.abstract}dd 八進制換碼字符, dd代表八進制數字。 
	/xXXXX或/x{XXXX} 4位十六進制Unicode字符, XXXX代表十六進制數字。 
	/cZ Z-'@' 控制字符Control-Z, Z為大于等與"@"的ASCII字符 
	2.2.3 換碼字符 
	/w 任一單詞字符, 如A-Z, a-z, 0-9, _等, 如 /w/w/w可以匹配 U_4 但不匹配 %^e 
	/W 任一非單詞字符, 如 /W/W 可以匹配 *& 但不匹配 7# 
	/s 任一空白字符,包括空格、制表符、換頁符、回車符和垂直制表符。= [ /f/n/r/t/v] 
	/S 任一非空白字符. = [^ /f/n/r/t/v] 
	/d 0-9的任一數字字符, 如 /d/d可以匹配 54 但不匹配 a4 
	/D 任一非數字字符. 如 /D/D可以匹配 a4 但不匹配 54 
	/l a-z 之間的任一小寫字符, 如 /l/l/l可以匹配 ccf 但不匹配 ccF 
	/L 任一非小寫字符, 如 /L/L/L可以匹配 CCF 但不匹配 cCF 
	/u a-z 之間的任一大寫字符, 如 /u/u/u可以匹配 CCF 但不匹配 CCf 
	/U 任一非大寫字符, 如 /U/U/U可以匹配 ccf 但不匹配 ccF 
	/C 任一字符, = '.' 
	/Q 前置引號符, 其后的任意字符均被認為普通字符直至出現后置引號符/E. 同時匹配單引號和雙引號 
	/E 后置引號符 
	2.2.4 轉義字符串 
	表示為[:classname:], 如"[[:space:]]"表示所有的空格字符 
	
	alnum 任一單詞字符和數字字符. = [/w/d] 
	alpha 任何一個單詞字符, 如A-Z, a-z, 0-9 
	blank 任一空白字符,包括空格、制表符、換頁符、回車符和垂直制表符。= [ /f/n/r/t/v] = /s 
	cntrl 任一控制字符. 
	digit 0-9的任一數字字符, = /d 
	graph 任一圖形字符. 
	lower a-z 之間的任一小寫字符 =/l 
	print 任一可打印字符 = '.' = /C 
	punct 任一標點符號 
	space 任一空格字符 
	upper a-z 之間的任一大寫字符 = /u 
	xdigit 4位十六進制Unicode字符, = /xXXXX 
	word 任何一個單詞字符, 如A-Z, a-z, 0-9, _等, = /w 
	unicode 任何一個ASCII值大于255的字符 
	2.2.5 定位字符 
	定位字符可以把正則表達式固定到行首或行尾。在Perl正則全集中還能使正則表達式出現在一個單詞內、在一個單詞的開頭或者一個單詞的結尾, emeditor只是一個子集, 不包含這個功能。 
	^ 匹配輸入字符串開始的位置。如果設置customize中的"regular expressions can match new line characters",那么 ^ 還匹配 /n 或 /r 后面的位置。 但在中括號表達式中使用的情況除外,在那種情況下它對字符集求反。 
	$ 匹配輸入字符串結尾的位置。如果設置customize中的"regular expressions can match new line characters",那么 $ 還匹配 /n 或 /r 前面的位置。 
	3. 分組捕獲和替換 
	
	分組通常用來捕獲特定模式的一組文本, 并用與之后的替換操作, 這也就是將分組和替換結合起來講解的原因. 
	最基本的分組構造方式就是(),在左右括號中括起來的部分,就是一個分組;在正則全集中還有如(?<name> )的命名分組方式,這種方式組合了模式在就是對分組的部分進行了命名,這樣就可以通過該組的命名來獲取信息, 但這種方式在emeditor中不被支持. 以下分別來介紹各種不同的分組: 
	
	() 組捕獲. 這種分組對模式在括號內所捕獲的字符進行組合, 并且每個分組捕獲的匹配結果都將保存為一個實體以備其后的操作所引用. 甚至在正則全集中還可對前面的分組進行反向引用(這是題外話, emeditor不支持). 舉例說明: 
	源文本: 
	
	代碼: 
	
	-------------------------------------------------------------------------------- 
	site status- online members: 65, online guests: 12 
	-------------------------------------------------------------------------------- 
	
	使用正則表達式: 
	
	代碼: 
	
	-------------------------------------------------------------------------------- 
	(members|guests): /d+ 
	-------------------------------------------------------------------------------- 
	
	括號中有兩個可能的匹配: members 和 guests, 只需要匹配其中任意一個; 其后是冒號和一個空格, 最后匹配至少一個數字. 匹配模式結果如下: 
	
	
	代碼: 
	
	-------------------------------------------------------------------------------- 
	members: 65 
	guests: 12 
	-------------------------------------------------------------------------------- 
	
	其中members和guests在兩次匹配中被捕捉, 可以在隨后的操作中引用. 
	
	
	(?:) 非組捕獲. 這種分組僅僅對模式在括號內所匹配的字符進行組合, 模式所匹配的字符將不會作為一個組來捕獲. 雖然他也同樣成為最終的匹配結果的一部分, 但無法為其后的操作所引用. 同樣以上例繼續: 
	使用正則表達式: 
	
	
	代碼: 
	
	
	-------------------------------------------------------------------------------- 
	(?:members|guests): /d+ 
	-------------------------------------------------------------------------------- 
	
	匹配模式結果同樣為: 
	
	
	代碼: 
	
	-------------------------------------------------------------------------------- 
	members: 65 
	guests: 12 
	-------------------------------------------------------------------------------- 
	
	但是members和guests僅僅在兩次匹配中被分組, 并不被捕獲, 也不可以在隨后的操作中引用. 
	使用非捕獲組有其原因和場合. 其一, 從效率上說, 捕獲一個分組需要消耗額外的資源和處理時間, 所以不應該捕獲不需要使用的數據. 其二, 對模式中有多個捕獲組的情況, 對不需要處理的分組進行捕獲只會對分組信息造成混亂. 其三, 避免不需要貪婪匹配的場合發生貪婪匹配, 貪婪匹配是正則引擎的一個重要特性, 要說清楚其機理可能還需要另外開一個專題了. 對這一點, 還以上例說明一下: 
	使用不帶分組的正則表達式: 
	
	代碼: 
	
	-------------------------------------------------------------------------------- 
	members|guests: /d+ 
	-------------------------------------------------------------------------------- 
	
	匹配模式為: 
	
	
	代碼: 
	
	-------------------------------------------------------------------------------- 
	members 
	guests: 12 
	-------------------------------------------------------------------------------- 
	
	
	這個正則表達式的問題在于, 他匹配的是"members" 或 "guests: /d+", 這是模式中貪婪"消費"字符引起的. 而通過增加括號進行分組, 使正則引擎將兩個匹配選項作為一個組處理, 從而正確匹配其中的一個匹配項. 
	
	
	(?=) 正聲明組, 非捕獲. 此分組中的模式必須出現在聲明的右側, 并且, 這個模式不構成匹配結果的一部分. 舉例: 
	源文本: 
	
	代碼: 
	
	-------------------------------------------------------------------------------- 
	site status- online members: 65, online guests: 12 
	-------------------------------------------------------------------------------- 
	
	
	使用正則表達式: 
	
	
	代碼: 
	
	
	-------------------------------------------------------------------------------- 
	/S+(?=/s/d+) 
	-------------------------------------------------------------------------------- 
	
	
	此模式中規定了/s/d+必須出現在/S+聲明的右側. 也就是說, 在至少一個非空格字符(聲明)的右側必須出現一個空格字符和至少一個數字, 而且只有這個聲明構成匹配結果. 匹配模式結果如下: 
	
	
	代碼: 
	
	
	-------------------------------------------------------------------------------- 
	members: 
	guests: 
	-------------------------------------------------------------------------------- 
	
	
	這兩次匹配中不被捕捉. 
	
	
	(?!) 負聲明組, 非捕獲. 此分組中的模式不得出現在聲明的右側, 并且, 這個模式不構成匹配結果的一部分. 還是用上面的例子: 
	使用正則表達式: 
	
	
	代碼: 
	
	
	-------------------------------------------------------------------------------- 
	/d{2}(?!,) 
	-------------------------------------------------------------------------------- 
	
	
	此模式中規定了","不得出現在/d{2}聲明的右側. 也就是說, 在連續兩個數字(聲明)的右側不得出現逗號才能被匹配. 匹配模式結果如下: 
	
	
	代碼: 
	
	
	-------------------------------------------------------------------------------- 
	12 
	-------------------------------------------------------------------------------- 
	
	
	這兩次匹配中不被捕捉. 
	嚴格的說, 后面兩個分組不能稱之為分組, 他們只是模式聲明, 他們不能成為匹配結果, 也不能被捕獲. 在正則全集中, 還有反向聲明分組(?<=)(?<!)和非回溯分組(?>), 在emeditor中不被支持. 
	
	
	說到括號的功能, 本來正則中的一個重要指令-條件指令和分組內聯設定是不得不說的, 可惜的是... emeditor也同樣不支持~~~~ 
	
	
	在前面的例子中一直提到匹配之后的操作, 而這個進一步的操作最常見的就是替換. 先繼續上面的例子: 
	源文本: 
	
	
	代碼: 
	
	
	-------------------------------------------------------------------------------- 
	site status- online members: 65, online guests: 12 
	-------------------------------------------------------------------------------- 
	
	
	使用搜索正則表達式: 
	
	
	代碼: 
	
	
	-------------------------------------------------------------------------------- 
	(members|guests) 
	-------------------------------------------------------------------------------- 
	
	
	和替換正則表達式: 
	
	
	代碼: 
	
	
	-------------------------------------------------------------------------------- 
	ccf- 
	-------------------------------------------------------------------------------- 
	
	
	匹配模式結果如下: 
	
	
	代碼: 
	
	
	-------------------------------------------------------------------------------- 
	members 
	guests 
	-------------------------------------------------------------------------------- 
	
	
	替換后的文本為: 
	
	
	代碼: 
	
	
	-------------------------------------------------------------------------------- 
	site status- online ccf-members: 65, online ccf-guests: 12 
	-------------------------------------------------------------------------------- 
	
	
	其中members和guests在兩次匹配中被捕捉, 在隨后被引用, 并添加ccf-前綴后替換源文本中的匹配字符. 
	在匹配模式中的分組匹配結果將按前后順序被正則引擎分別賦予內部組號, 在替換操作中就可以用/加上這個組號來引用相應的匹配結果. 繼續上例: 
	使用搜索正則表達式: 
	
	
	代碼: 
	
	
	-------------------------------------------------------------------------------- 
	(members|guests): (/d{2}) 
	-------------------------------------------------------------------------------- 
	
	
	和替換正則表達式: 
	
	
	代碼: 
	
	
	-------------------------------------------------------------------------------- 
	ccf- = 
	-------------------------------------------------------------------------------- 
	
	
	匹配模式結果如下: 
	
	
	代碼: 
	
	
	-------------------------------------------------------------------------------- 
	members: 65 
	guests: 12 
	-------------------------------------------------------------------------------- 
	
	
	替換后的文本為: 
	
	
	代碼: 
	
	
	-------------------------------------------------------------------------------- 
	site status- online ccf-members = 65, online ccf-guests = 12 
	-------------------------------------------------------------------------------- 
	
	
	
	
	在emeditor的正則子集中增加了一個特殊的引用: {post.abstract} , {post.abstract} 將引用上次的匹配結果, 繼續把: 
	使用搜索正則表達式: 
	
	
	代碼: 
	
	
	-------------------------------------------------------------------------------- 
	/d{2} 
	-------------------------------------------------------------------------------- 
	
	
	和替換正則表達式: 
	
	
	代碼: 
	
	
	-------------------------------------------------------------------------------- 
	*{post.abstract}* 
	-------------------------------------------------------------------------------- 
	
	
	匹配模式結果如下: 
	
	
	代碼: 
	
	
	-------------------------------------------------------------------------------- 
	65 
	12 
	-------------------------------------------------------------------------------- 
	
	
	替換后的文本為: 
	
	
	代碼: 
	
	
	-------------------------------------------------------------------------------- 
	site status- online ccf-members: *65*, online ccf-guests: *12* 
	-------------------------------------------------------------------------------- 
	
	作為一個編輯軟件, emeditor的正則子集中增加了一些替換修飾符: 
	
	/U 大寫修飾. 將其后的所有的字符替換為大寫 
	/L 小寫修飾. 將其后的所有的字符替換為小寫 
	/H 半角修飾. 將其后的所有的字符替換為半角字符. 寫到這里, 不得不稱許一下emeditor對中文的良好支持, 這個/H至少我是很常用的, 不喜歡看到文本里面都是些123abc之類的全角字符... 
	/F 全角修飾. 將其后的所有的字符替換為全角字符 
	/E 關閉之前的/U, /L, /H, /F修飾. 
	^[  /t]*/n 
	這個正則表達式代表所有的空行,指含有零個或零個以上空格或制表符、以換行符結尾、不含其它字符的行。 
	
	(^|(?<=中國)).*?(?=中國|$) 
	用正則表達式匹配特定字符串外的所有字符。指除“中國”外的所有其它字符,類似于反選功能。 
	
	^[  /t]+ 
	查找以上字符,并替換為空,可刪除行首空白(包括全半角空格和制表符)。 
	
	[  /t]+$ 
	查找以上字符,并替換為空,可刪除行末空白(包括全半角空格和制表符)。 
	
	
	^[  /t]+|[  /t]+$ 
	查找以上正則表達式,并替換為空,可刪除行首和行末所有空白(包括全半角空格和制表符)。
	
	匹配中文字符的正則表達式: [/u4e00-/u9fa5] 
	評注:匹配中文還真是個頭疼的事,有了這個表達式就好辦了 
	
	匹配雙字節字符(包括漢字在內):[^/x00-/xff] 
	評注:可以用來計算字符串的長度(一個雙字節字符長度計2,ASCII字符計1) 
	
	匹配空白行的正則表達式:/n/s*/r 
	評注:可以用來刪除空白行 
	
	匹配HTML標記的正則表達式:< (/S*?)[^>]*>.*?|< .*? /> 
	評注:網上流傳的版本太糟糕,上面這個也僅僅能匹配部分,對于復雜的嵌套標記依舊無能為力 
	
	
	匹配首尾空白字符的正則表達式:^/s*|/s*$ 
	評注:可以用來刪除行首行尾的空白字符(包括空格、制表符、換頁符等等),非常有用的表達式 
	
	匹配Email地址的正則表達式:/w+([-+.]/w+)*@/w+([-.]/w+)*/./w+([-.]/w+)* 
	評注:表單驗證時很實用 
	
	匹配網址URL的正則表達式:[a-zA-z]+://[^/s]* 
	評注:網上流傳的版本功能很有限,上面這個基本可以滿足需求 
	
	匹配帳號是否合法(字母開頭,允許5-16字節,允許字母數字下劃線):^[a-zA-Z][a-zA-Z0-9_]{4,15}$ 
	評注:表單驗證時很實用 
	
	匹配國內電話號碼:/d{3}-/d{8}|/d{4}-/d{7} 
	評注:匹配形式如 0511-4405222 或 021-87888822 
	
	匹配騰訊QQ號:[1-9][0-9]{4,} 
	評注:騰訊QQ號從10000開始 
	
	
	匹配中國郵政編碼:[1-9]/d{5}(?!/d) 
	評注:中國郵政編碼為6位數字 
	
	匹配身份證:/d{15}|/d{18} 
	評注:中國的身份證為15位或18位 
	
	匹配ip地址:/d+/./d+/./d+/./d+ 
	評注:提取ip地址時有用 
	
	匹配特定數字: 
	^[1-9]/d*$    //匹配正整數 
	^-[1-9]/d*$   //匹配負整數 
	^-?[1-9]/d*$   //匹配整數 
	^[1-9]/d*|0$  //匹配非負整數(正整數 + 0) 
	^-[1-9]/d*|0$   //匹配非正整數(負整數 + 0) 
	^[1-9]/d*/./d*|0/./d*[1-9]/d*$   //匹配正浮點數 
	^-([1-9]/d*/./d*|0/./d*[1-9]/d*)$  //匹配負浮點數 
	^-?([1-9]/d*/./d*|0/./d*[1-9]/d*|0?/.0+|0)$  //匹配浮點數 
	^[1-9]/d*/./d*|0/./d*[1-9]/d*|0?/.0+|0$   //匹配非負浮點數(正浮點數 + 0) 
	^(-([1-9]/d*/./d*|0/./d*[1-9]/d*))|0?/.0+|0$  //匹配非正浮點數(負浮點數 + 0) 
	評注:處理大量數據時有用,具體應用時注意修正 
	
	匹配特定字符串: 
	^[A-Za-z]+$  //匹配由26個英文字母組成的字符串 
	^[A-Z]+$  //匹配由26個英文字母的大寫組成的字符串 
	^[a-z]+$  //匹配由26個英文字母的小寫組成的字符串 
	^[A-Za-z0-9]+$  //匹配由數字和26個英文字母組成的字符串 
	^/w+$  //匹配由數字、26個英文字母或者下劃線組成的字符串 
	評注:最基本也是最常用的一些表達式 
	
	^.*John.*$ 
	匹配包括“John”的整行。 
新聞熱點
疑難解答