從制造到創造
軟件工程師成長之路 |
作者:笑容
發表于:2004年05月03日
最后更新:2005年01月17日 19:54
版權聲明:使用
創作公用版權協議
前言
正則表達式是煩瑣的,但是強大的,學會之后的應用會讓你除了提高效率外,會給你帶來絕對的成就感。只要認真去閱讀這些資料,加上應用的時候進行一定的參考,掌握正則表達式不是問題。
索引
4._各種操作符的運算優先級
5._全部符號解釋
6._部分例子
7._正則表達式匹配規則
目前,正則表達式已經在很多軟件中得到廣泛的應用,包括*nix(Linux, Unix等),HP等操作系統,PHP,C#,Java等開發環境,以及很多的應用軟件中,都可以看到正則表達式的影子。
正則表達式的使用,可以通過簡單的辦法來實現強大的功能。為了簡單有效而又不失強大,造成了正則表達式代碼的難度較大,學習起來也不是很容易,所以需要付出一些努力才行,入門之后參照一定的參考,使用起來還是比較簡單有效的。
例子: ^.+@.+\\..+$
這樣的代碼曾經多次把我自己給嚇退過。可能很多人也是被這樣的代碼給嚇跑的吧。繼續閱讀本文將讓你也可以自由應用這樣的代碼。
注意:這里的第7部分跟前面的內容看起來似乎有些重復,目的是把前面表格里的部分重新描述了一次,目的是讓這些內容更容易理解。
1956 年, 一位叫 Stephen Kleene 的數學家在 McCulloch 和 Pitts 早期工作的基礎上,發表了一篇標題為“神經網事件的表示法”的論文,引入了正則表達式的概念。正則表達式就是用來描述他稱為“正則集的代數”的表達式,因此采用“正則表達式”這個術語。
隨后,發現可以將這一工作應用于使用 Ken Thompson 的計算搜索算法的一些早期研究,Ken Thompson 是 Unix 的主要發明人。正則表達式的第一個實用應用程序就是 Unix 中的 qed 編輯器。
如他們所說,剩下的就是眾所周知的歷史了。從那時起直至現在正則表達式都是基于文本的編輯器和搜索工具中的一個重要部分。
正則表達式(regular expression)描述了一種字符串匹配的模式,可以用來檢查一個串是否含有某種子串、將匹配的子串做替換或者從某個串中取出符合某個條件的子串等。
- 列目錄時, dir *.txt或ls *.txt中的*.txt就 不 是一個正則表達式,因為這里*與正則式的*的含義是不同的。
正則表達式是由普通字符(例如字符 a 到 z)以及特殊字符(稱為元字符)組成的文字模式。正則表達式作為一個模板,將某個字符模式與所搜索的字符串進行匹配。
由所有那些未顯式指定為元字符的打印和非打印字符組成。這包括所有的大寫和小寫字母字符,所有數字,所有標點符號以及一些符號。
字符 | 含義 |
---|---|
\cx | 匹配由x指明的控制字符。例如, \cM 匹配一個 Control-M 或回車符。x 的值必須為 A-Z 或 a-z 之一。否則,將 c 視為一個原義的 'c' 字符。 |
\f | 匹配一個換頁符。等價于 \x0c 和 \cL。 |
\n | 匹配一個換行符。等價于 \x0a 和 \cJ。 |
\r | 匹配一個回車符。等價于 \x0d 和 \cM。 |
\s | 匹配任何空白字符,包括空格、制表符、換頁符等等。等價于 [ \f\n\r\t\v]。 |
\S | 匹配任何非空白字符。等價于 [^ \f\n\r\t\v]。 |
\t | 匹配一個制表符。等價于 \x09 和 \cI。 |
\v | 匹配一個垂直制表符。等價于 \x0b 和 \cK。 |
特別字符 | 說明 |
---|---|
$ | 匹配輸入字符串的結尾位置。如果設置了 RegExp 對象的 Multiline 屬性,則 $ 也匹配 '\n' 或 '\r'。要匹配 $ 字符本身,請使用 \$。 |
( ) | 標記一個子表達式的開始和結束位置。子表達式可以獲取供以后使用。要匹配這些字符,請使用 \( 和 \)。 |
* | 匹配前面的子表達式零次或多次。要匹配 * 字符,請使用 \*。 |
+ | 匹配前面的子表達式一次或多次。要匹配 + 字符,請使用 \+。 |
. | 匹配除換行符 \n之外的任何單字符。要匹配 .,請使用 \。 |
[ | 標記一個中括號表達式的開始。要匹配 [,請使用 \[。 |
? | 匹配前面的子表達式零次或一次,或指明一個非貪婪限定符。要匹配 ? 字符,請使用 \?。 |
\ | 將下一個字符標記為或特殊字符、或原義字符、或向后引用、或八進制轉義符。例如, 'n' 匹配字符 'n'。'\n' 匹配換行符。序列 '\\' 匹配 "\",而 '\(' 則匹配 "("。 |
^ | 匹配輸入字符串的開始位置,除非在方括號表達式中使用,此時它表示不接受該字符集合。要匹配 ^ 字符本身,請使用 \^。 |
{ | 標記限定符表達式的開始。要匹配 {,請使用 \{。 |
| | 指明兩項之間的一個選擇。要匹配 |,請使用 \|。 |
- 構造正則表達式的方法和創建數學表達式的方法一樣。也就是用多種元字符與操作符將小的表達式結合在一起來創建更大的表達式。正則表達式的組件可以是單個的字符、字符集合、字符范圍、字符間的選擇或者所有這些組件的任意組合。
字符 | 描述 |
---|---|
* | 匹配前面的子表達式零次或多次。例如,zo* 能匹配 "z" 以及 "zoo"。* 等價于{0,}。 |
+ | 匹配前面的子表達式一次或多次。例如,'zo+' 能匹配 "zo" 以及 "zoo",但不能匹配 "z"。+ 等價于 {1,}。 |
? | 匹配前面的子表達式零次或一次。例如,"do(es)?" 可以匹配 "do" 或 "does" 中的"do" 。? 等價于 {0,1}。 |
{n} | n 是一個非負整數。匹配確定的 n 次。例如,'o{2}' 不能匹配 "Bob" 中的 'o',但是能匹配 "food" 中的兩個 o。 |
{n,} | n 是一個非負整數。至少匹配n 次。例如,'o{2,}' 不能匹配 "Bob" 中的 'o',但能匹配 "foooood" 中的所有 o。'o{1,}' 等價于 'o+'。'o{0,}' 則等價于 'o*'。 |
{n,m} | m 和 n 均為非負整數,其中n <= m。最少匹配 n 次且最多匹配 m 次。例如,"o{1,3}" 將匹配 "fooooood" 中的前三個 o。'o{0,1}' 等價于 'o?'。請注意在逗號和兩個數之間不能有空格。 |
操作符 | 描述 |
---|---|
\ | 轉義符 |
(), (?:), (?=), [] | 圓括號和方括號 |
*, +, ?, {n}, {n,}, {n,m} | 限定符 |
^, $, \anymetacharacter | 位置和順序 |
| | “或”操作 |
字符 | 描述 |
---|---|
\ | 將下一個字符標記為一個特殊字符、或一個原義字符、或一個 向后引用、或一個八進制轉義符。例如,'n' 匹配字符 "n"。'\n' 匹配一個換行符。序列 '\\' 匹配 "\" 而 "\(" 則匹配 "("。 |
^ | 匹配輸入字符串的開始位置。如果設置了 RegExp 對象的 Multiline 屬性,^ 也匹配 '\n' 或 '\r' 之后的位置。 |
$ | 匹配輸入字符串的結束位置。如果設置了RegExp 對象的 Multiline 屬性,$ 也匹配 '\n' 或 '\r' 之前的位置。 |
* | 匹配前面的子表達式零次或多次。例如,zo* 能匹配 "z" 以及 "zoo"。* 等價于{0,}。 |
+ | 匹配前面的子表達式一次或多次。例如,'zo+' 能匹配 "zo" 以及 "zoo",但不能匹配 "z"。+ 等價于 {1,}。 |
? | 匹配前面的子表達式零次或一次。例如,"do(es)?" 可以匹配 "do" 或 "does" 中的"do" 。? 等價于 {0,1}。 |
{n} | n 是一個非負整數。匹配確定的 n 次。例如,'o{2}' 不能匹配 "Bob" 中的 'o',但是能匹配 "food" 中的兩個 o。 |
{n,} | n 是一個非負整數。至少匹配n 次。例如,'o{2,}' 不能匹配 "Bob" 中的 'o',但能匹配 "foooood" 中的所有 o。'o{1,}' 等價于 'o+'。'o{0,}' 則等價于 'o*'。 |
{n,m} | m 和 n 均為非負整數,其中n <= m。最少匹配 n 次且最多匹配 m 次。例如,"o{1,3}" 將匹配 "fooooood" 中的前三個 o。'o{0,1}' 等價于 'o?'。請注意在逗號和兩個數之間不能有空格。 |
? | 當該字符緊跟在任何一個其他限制符 (*, +, ?, {n}, {n,}, {n,m}) 后面時,匹配模式是非貪婪的。非貪婪模式盡可能少的匹配所搜索的字符串,而默認的貪婪模式則盡可能多的匹配所搜索的字符串。例如,對于字符串 "oooo",'o+?' 將匹配單個 "o",而 'o+' 將匹配所有 'o'。 |
. | 匹配除 "\n" 之外的任何單個字符。要匹配包括 '\n' 在內的任何字符,請使用象 '[.\n]' 的模式。 |
(pattern) | 匹配 pattern 并獲取這一匹配。所獲取的匹配可以從產生的 Matches 集合得到,在VBScript 中使用 SubMatches 集合,在JScript 中則使用 $0…$9 屬性。要匹配圓括號字符,請使用 '\(' 或 '\)'。 |
(?:pattern) | 匹配 pattern 但不獲取匹配結果,也就是說這是一個非獲取匹配,不進行存儲供以后使用。這在使用 "或" 字符 (|) 來組合一個模式的各個部分是很有用。例如, 'industr(?:y|ies) 就是一個比 'industry|industries' 更簡略的表達式。 |
(?=pattern) | 正向預查,在任何匹配 pattern 的字符串開始處匹配查找字符串。這是一個非獲取匹配,也就是說,該匹配不需要獲取供以后使用。例如,'Windows (?=95|98|NT|2000)' 能匹配 "Windows 2000" 中的 "Windows" ,但不能匹配 "Windows 3.1" 中的 "Windows"。預查不消耗字符,也就是說,在一個匹配發生后,在最后一次匹配之后立即開始下一次匹配的搜索,而不是從包含預查的字符之后開始。 |
(?!pattern) | 負向預查,在任何不匹配 pattern 的字符串開始處匹配查找字符串。這是一個非獲取匹配,也就是說,該匹配不需要獲取供以后使用。例如'Windows (?!95|98|NT|2000)' 能匹配 "Windows 3.1" 中的 "Windows",但不能匹配 "Windows 2000" 中的 "Windows"。預查不消耗字符,也就是說,在一個匹配發生后,在最后一次匹配之后立即開始下一次匹配的搜索,而不是從包含預查的字符之后開始 |
x|y | 匹配 x 或 y。例如,'z|food' 能匹配 "z" 或 "food"。'(z|f)ood' 則匹配 "zood" 或 "food"。 |
[xyz] | 字符集合。匹配所包含的任意一個字符。例如, '[abc]' 可以匹配 "plain" 中的 'a'。 |
[^xyz] | 負值字符集合。匹配未包含的任意字符。例如, '[^abc]' 可以匹配 "plain" 中的'p'。 |
[a-z] | 字符范圍。匹配指定范圍內的任意字符。例如,'[a-z]' 可以匹配 'a' 到 'z' 范圍內的任意小寫字母字符。 |
[^a-z] | 負值字符范圍。匹配任何不在指定范圍內的任意字符。例如,'[^a-z]' 可以匹配任何不在 'a' 到 'z' 范圍內的任意字符。 |
\b | 匹配一個單詞邊界,也就是指單詞和空格間的位置。例如, 'er\b' 可以匹配"never" 中的 'er',但不能匹配 "verb" 中的 'er'。 |
\B | 匹配非單詞邊界。'er\B' 能匹配 "verb" 中的 'er',但不能匹配 "never" 中的 'er'。 |
\cx | 匹配由 x 指明的控制字符。例如, \cM 匹配一個 Control-M 或回車符。x 的值必須為 A-Z 或 a-z 之一。否則,將 c 視為一個原義的 'c' 字符。 |
\d | 匹配一個數字字符。等價于 [0-9]。 |
\D | 匹配一個非數字字符。等價于 [^0-9]。 |
\f | 匹配一個換頁符。等價于 \x0c 和 \cL。 |
\n | 匹配一個換行符。等價于 \x0a 和 \cJ。 |
\r | 匹配一個回車符。等價于 \x0d 和 \cM。 |
\s | 匹配任何空白字符,包括空格、制表符、換頁符等等。等價于 [ \f\n\r\t\v]。 |
\S | 匹配任何非空白字符。等價于 [^ \f\n\r\t\v]。 |
\t | 匹配一個制表符。等價于 \x09 和 \cI。 |
\v | 匹配一個垂直制表符。等價于 \x0b 和 \cK。 |
\w | 匹配包括下劃線的任何單詞字符。等價于'[A-Za-z0-9_]'。 |
\W | 匹配任何非單詞字符。等價于 '[^A-Za-z0-9_]'。 |
\xn | 匹配 n,其中 n 為十六進制轉義值。十六進制轉義值必須為確定的兩個數字長。例如,'\x41' 匹配 "A"。'\x041' 則等價于 '\x04' & "1"。正則表達式中可以使用 ASCII 編碼。. |
\num | 匹配 num,其中 num 是一個正整數。對所獲取的匹配的引用。例如,'(.)\1' 匹配兩個連續的相同字符。 |
\n | 標識一個八進制轉義值或一個向后引用。如果 \n 之前至少 n 個獲取的子表達式,則 n 為向后引用。否則,如果 n 為八進制數字 (0-7),則 n 為一個八進制轉義值。 |
\nm | 標識一個八進制轉義值或一個向后引用。如果 \nm 之前至少有 nm 個獲得子表達式,則 nm 為向后引用。如果 \nm 之前至少有 n 個獲取,則 n 為一個后跟文字 m 的向后引用。如果前面的條件都不滿足,若 n 和 m 均為八進制數字 (0-7),則 \nm 將匹配八進制轉義值 nm。 |
\nml | 如果 n 為八進制數字 (0-3),且 m 和 l 均為八進制數字 (0-7),則匹配八進制轉義值 nml。 |
\un | 匹配 n,其中 n 是一個用四個十六進制數字表示的 Unicode 字符。例如, \u00A9 匹配版權符號 (?)。 |
正則表達式 | 說明 |
---|---|
/\b([a-z]+) \1\b/gi | 一個單詞連續出現的位置 |
/(\w+):\/\/([^/:]+)(:\d*)?([^# ]*)/ | 將一個URL解析為協議、域、端口及相對路徑 |
/^(?:Chapter|Section) [1-9][0-9]{0,1}$/ | 定位章節的位置 |
/[-a-z]/ | A至z共26個字母再加一個-號。 |
/ter\b/ | 可匹配chapter,而不能terminal |
/\Bapt/ | 可匹配chapter,而不能aptitude |
/Windows(?=95 |98 |NT )/ | 可匹配Windows95或Windows98或WindowsNT,當找到一個匹配后,從Windows后面開始進行下一次的檢索匹配。 |
7.1 基本模式匹配
一切從最基本的開始。模式,是正規表達式最基本的元素,它們是一組描述字符串特征的字符。模式可以很簡單,由普通的字符串組成,也可以非常復雜,往往用特殊的字符表示一個范圍內的字符、重復出現,或表示上下文。例如:
^once
這個模式包含一個特殊的字符^,表示該模式只匹配那些以once開頭的字符串。例如該模式與字符串"once upon a time"匹配,與"There once was a man from NewYork"不匹配。正如如^符號表示開頭一樣,$符號用來匹配那些以給定模式結尾的字符串。
bucket$
這個模式與"Who kept all of this cash in a bucket"匹配,與"buckets"不匹配。字符^和$同時使用時,表示精確匹配(字符串與模式一樣)。例如:
^bucket$
只匹配字符串"bucket"。如果一個模式不包括^和$,那么它與任何包含該模式的字符串匹配。例如:模式
once
與字符串
There once was a man from NewYork
Who kept all of his cash in a bucket.
是匹配的。
在該模式中的字母(o-n-c-e)是字面的字符,也就是說,他們表示該字母本身,數字也是一樣的。其他一些稍微復雜的字符,如標點符號和白字符(空格、制表符等),要用到轉義序列。所有的轉義序列都用反斜杠(\)打頭。制表符的轉義序列是:\t。所以如果我們要檢測一個字符串是否以制表符開頭,可以用這個模式:
^\t
類似的,用\n表示“新行”,\r表示回車。其他的特殊符號,可以用在前面加上反斜杠,如反斜杠本身用\\表示,句號.用\.表示,以此類推。
7.2 字符簇
在INTERNET的程序中,正規表達式通常用來驗證用戶的輸入。當用戶提交一個FORM以后,要判斷輸入的電話號碼、地址、EMAIL地址、信用卡號碼等是否有效,用普通的基于字面的字符是不夠的。
所以要用一種更自由的描述我們要的模式的辦法,它就是字符簇。要建立一個表示所有元音字符的字符簇,就把所有的元音字符放在一個方括號里:
[AaEeIiOoUu]
這個模式與任何元音字符匹配,但只能表示一個字符。用連字號可以表示一個字符的范圍,如:
[a-z] //匹配所有的小寫字母
[A-Z] //匹配所有的大寫字母
[a-zA-Z] //匹配所有的字母
[0-9] //匹配所有的數字
[0-9\.\-] //匹配所有的數字,句號和減號
[ \f\r\t\n] //匹配所有的白字符
同樣的,這些也只表示一個字符,這是一個非常重要的。如果要匹配一個由一個小寫字母和一位數字組成的字符串,比如"z2"、"t6"或"g7",但不是"ab2"、"r2d3" 或"b52"的話,用這個模式:
^[a-z][0-9]$
盡管[a-z]代表26個字母的范圍,但在這里它只能與第一個字符是小寫字母的字符串匹配。
前面曾經提到^表示字符串的開頭,但它還有另外一個含義。當在一組方括號里使用^是,它表示“非”或“排除”的意思,常常用來剔除某個字符。還用前面的例子,我們要求第一個字符不能是數字:
^[^0-9][0-9]$
這個模式與"&5"、"g7"及"-2"是匹配的,但與"12"、"66"是不匹配的。下面是幾個排除特定字符的例子:
[^a-z] //除了小寫字母以外的所有字符
[^\\\/\^] //除了(\)(/)(^)之外的所有字符
[^\"\'] //除了雙引號(")和單引號(')之外的所有字符
特殊字符"." (點,句號)在正規表達式中用來表示除了“新行”之外的所有字符。所以模式"^.5$"與任何兩個字符的、以數字5結尾和以其他非“新行”字符開頭的字符串匹配。模式"."可以匹配任何字符串,除了空串和只包括一個“新行”的字符串。
PHP的正規表達式有一些內置的通用字符簇,列表如下:
字符簇 含義
[[:alpha:]] 任何字母
[[:digit:]] 任何數字
[[:alnum:]] 任何字母和數字
[[:space:]] 任何白字符
[[:upper:]] 任何大寫字母
[[:lower:]] 任何小寫字母
[[:punct:]] 任何標點符號
[[:xdigit:]] 任何16進制的數字,相當于[0-9a-fA-F]
7.3 確定重復出現
到現在為止,你已經知道如何去匹配一個字母或數字,但更多的情況下,可能要匹配一個單詞或一組數字。一個單詞有若干個字母組成,一組數字有若干個單數組成。跟在字符或字符簇后面的花括號({})用來確定前面的內容的重復出現的次數。
字符簇 含義
^[a-zA-Z_]$ 所有的字母和下劃線
^[[:alpha:]]{3}$ 所有的3個字母的單詞
^a$ 字母a
^a{4}$ aaaa
^a{2,4}$ aa,aaa或aaaa
^a{1,3}$ a,aa或aaa
^a{2,}$ 包含多于兩個a的字符串
^a{2,} 如:aardvark和aaab,但apple不行
a{2,} 如:baad和aaa,但Nantucket不行
\t{2} 兩個制表符
.{2} 所有的兩個字符
這些例子描述了花括號的三種不同的用法。一個數字,{x}的意思是“前面的字符或字符簇只出現x次”;一個數字加逗號,{x,}的意思是“前面的內容出現x或更多的次數”;兩個用逗號分隔的數字,{x,y}表示“前面的內容至少出現x次,但不超過y次”。我們可以把模式擴展到更多的單詞或數字:
^[a-zA-Z0-9_]{1,}$ //所有包含一個以上的字母、數字或下劃線的字符串
^[0-9]{1,}$ //所有的正數
^\-{0,1}[0-9]{1,}$ //所有的整數
^\-{0,1}[0-9]{0,}\.{0,1}[0-9]{0,}$ //所有的小數
最后一個例子不太好理解,是嗎?這么看吧:與所有以一個可選的負號(\-{0,1})開頭(^)、跟著0個或更多的數字([0-9]{0,})、和一個可選的小數點(\.{0,1})再跟上0個或多個數字([0-9]{0,}),并且沒有其他任何東西($)。下面你將知道能夠使用的更為簡單的方法。
特殊字符"?"與{0,1}是相等的,它們都代表著:“0個或1個前面的內容”或“前面的內容是可選的”。所以剛才的例子可以簡化為:
^\-?[0-9]{0,}\.?[0-9]{0,}$
特殊字符"*"與{0,}是相等的,它們都代表著“0個或多個前面的內容”。最后,字符"+"與 {1,}是相等的,表示“1個或多個前面的內容”,所以上面的4個例子可以寫成:
^[a-zA-Z0-9_]+$ //所有包含一個以上的字母、數字或下劃線的字符串
^[0-9]+$ //所有的正數
^\-?[0-9]+$ //所有的整數
^\-?[0-9]*\.?[0-9]*$ //所有的小數
當然這并不能從技術上降低正規表達式的復雜性,但可以使它們更容易閱讀。
微軟MSDN上的例子(英文):
|
! 去除字符串兩端空格的處理
如果采用傳統的方式,就要可能就要采用下面的方式了
//清除左邊空格
function js_ltrim(deststr)
{
?if(deststr==null)return "";
?var pos=0;
?var retStr=new String(deststr);
?if (retStr.lenght==0) return retStr;
?while (retStr.substring(pos,pos+1)==" ") pos++;
?retStr=retStr.substring(pos);
?return(retStr);
}
//清除右邊空格
function js_rtrim(deststr)
{
?if(deststr==null)return "";
?var retStr=new String(deststr);
?var pos=retStr.length;
?if (pos==0) return retStr;
?while (pos && retStr.substring(pos-1,pos)==" " ) pos--;
?retStr=retStr.substring(0,pos);
?return(retStr);
}
//清除左邊和右邊空格
function js_trim(deststr)
{
?if(deststr==null)return "";
?var retStr=new String(deststr);
?var pos=retStr.length;
?if (pos==0) return retStr;
?retStr=js_ltrim(retStr);
?retStr=js_rtrim(retStr);
?return retStr;
}
采用正則表達式,來去除兩邊的空格,只需以下代碼
String.prototype.trim = function()
{
return this.replace(/(^\s*)|(\s*$)/g, "");
}
一句就搞定了,
可見正則表達式為我們節省了相當的編寫代碼量
! 移動手機號的校驗
如果采用傳統的校驗方式至少就要完成下面三步的校驗,
(1). 是否是數字
(2).是否是11位
(3).數字的第三位是否是5,6,7,8,9
如果采用正則表達式校驗,只需以下代碼
function checkMobile1(form)
{
if (form.mobile.value > "")
{
var reg=/13[5,6,7,8,9]\d{8}/;
if ( form.mobile.value.match(reg)== null)
{
alert("請輸入正確的移動手機號碼!");
form.mobile.focus(); return false;
?}
}
return true;
}
從上面的代碼可以看出校驗移動手機號只需定義一個var reg=/13[5,6,7,8,9]\d{8}/;模式匹配串就可以完成合法性校驗了
! URL的校驗,
條件:必須以http:// 或 https:// 開頭, 端口號必須為在1-65535 之間, 以下代碼完成了合法性校驗
//obj:數據對象
//dispStr :失敗提示內容顯示字符串
function checkUrlValid( obj,? dispStr)
{
?if(obj? == null)
?{
??alert("傳入對象為空");
??return false;
?}
?var str = obj.value;
?var? urlpatern0 = /^https?:\/\/.+$/i;
?if(!urlpatern0.test(str))
?{
??alert(dispStr+"不合法:必須以'http:\/\/'或'https:\/\/'開頭!");
??obj.focus();
??return false;
?}
?var? urlpatern2= /^https?:\/\/(([a-zA-Z0-9_-])+(\.)?)*(:\d+)?.+$/i;
?if(!urlpatern2.test(str))
?{
??alert(dispStr+"端口號必須為數字且應在1-65535之間!");
??obj.focus();
??return false;
?}
?var?urlpatern1 =/^https?:\/\/(([a-zA-Z0-9_-])+(\.)?)*(:\d+)?(\/((\.)?(\?)?=?&?[a-zA-Z0-9_-](\?)?)*)*$/i;
?if(!urlpatern1.test(str))
?{
??alert(dispStr+"不合法,請檢查!");
??obj.focus();
??return false;
?}
?var s = "0";
?var t =0;
? var re = new RegExp(":\\d+","ig");
? while((arr = re.exec(str))!=null)
?{
??s = str.substring(RegExp.index+1,RegExp.lastIndex);
??if(s.substring(0,1)=="0")
??{
???alert(dispStr+"端口號不能以0開頭!");
???obj.focus();
???return false;
??}
??t = parseInt(s);
??if(t<1 || t >65535)
??{
???alert(dispStr+"端口號必須為數字且應在1-65535之間!");
???obj.focus();
???return false;
??}
?}
?return true;
}
?
對url的校驗,看上去有很多的代碼,這是因為要給予出錯提示, 否則只需var?urlpatern1 =/^https?:\/\/(([a-zA-Z0-9_-])+(\.)?)*(:\d+)?(\/((\.)?(\?)?=?&?[a-zA-Z0-9_-](\?)?)*)*$/i; 一句就可以校驗出url合法性了。
javascript正則表達式檢驗
/*********************************************************************************
* EO_JSLib.js
* javascript正則表達式檢驗
**********************************************************************************/
//校驗是否全由數字組成
function isDigit(s)
{
var patrn=/^[0-9]{1,20}$/;
if (!patrn.exec(s)) return false
return true
}
//校驗登錄名:只能輸入5-20個以字母開頭、可帶數字、“_”、“.”的字串
function isRegisterUserName(s)
{
var patrn=/^[a-zA-Z]{1}([a-zA-Z0-9]|[._]){4,19}$/;
if (!patrn.exec(s)) return false
return true
}
//校驗用戶姓名:只能輸入1-30個以字母開頭的字串
function isTrueName(s)
{
var patrn=/^[a-zA-Z]{1,30}$/;
if (!patrn.exec(s)) return false
return true
}
//校驗密碼:只能輸入6-20個字母、數字、下劃線
function isPasswd(s)
{
var patrn=/^(\w){6,20}$/;
if (!patrn.exec(s)) return false
return true
}
//校驗普通電話、傳真號碼:可以“+”開頭,除數字外,可含有“-”
function isTel(s)
{
//var patrn=/^[+]{0,1}(\d){1,3}[ ]?([-]?(\d){1,12})+$/;
var patrn=/^[+]{0,1}(\d){1,3}[ ]?([-]?((\d)|[ ]){1,12})+$/;
if (!patrn.exec(s)) return false
return true
}
//校驗手機號碼:必須以數字開頭,除數字外,可含有“-”
function isMobil(s)
{
var patrn=/^[+]{0,1}(\d){1,3}[ ]?([-]?((\d)|[ ]){1,12})+$/;
if (!patrn.exec(s)) return false
return true
}
//校驗郵政編碼
function isPostalCode(s)
{
//var patrn=/^[a-zA-Z0-9]{3,12}$/;
var patrn=/^[a-zA-Z0-9 ]{3,12}$/;
if (!patrn.exec(s)) return false
return true
}
//校驗搜索關鍵字
function isSearch(s)
{
var patrn=/^[^`~!@#$%^&*()+=|\\\][\]\{\}:;'\,.<>/?]{1}[^`~!@$%^&()+=|\\\][\]\{\}:;'\,.<>?]{0,19}$/;
if (!patrn.exec(s)) return false
return true
}
function isIP(s) //by zergling
{
var patrn=/^[0-9.]{1,20}$/;
if (!patrn.exec(s)) return false
return true
}
(ip,email,data,time)
<script language="javascript">
??? var patterns = new Object();
??? //匹配ip地址
??? patterns.ip = /^(\d{1,2}|1\d\d|2[0-4]\d|25[0-5])(\.(\d{1,2}|1\d\d|2[0-4]\d|25[0-5])){3}$/;
??? //匹配郵件地址
??? patterns.email = /^[a-zA-Z0-9_-]+@[a-zA-Z0-9_-]+(\.[a-zA-Z0-9_-]+)+$/;
??? //匹配日期格式2008-01-31,但不匹配2008-13-00
??? patterns.date = /^\d{4}-(0?[1-9]|1[0-2])-(0?[1-9]|[1-2]\d|3[0-1])$/;
???
??? /**//*匹配時間格式00:15:39,但不匹配24:60:00,下面使用RegExp對象的構造方法
??? 來創建RegExp對象實例,注意正則表達式模式文本中的“\”要寫成“\\”*/
??? patterns.time = new RegExp("^([0-1]\\d|2[0-3]):[0-5]\\d:[0-5]\\d$");
???????
??? /**//*verify – 校驗一個字符串是否符合某種模式
???? *str – 要進行校驗的字符串
???? *pat – 與patterns中的某個正則表達式模式對應的屬性名稱
???? */
??? function verify(str,pat)
??? {???????
??????? thePat = patterns[pat];
??????? if(thePat.test(str))
??????? {
??????????? return true;
??????? }
??????? else
??????? {
??????????? return false;
??????? }
??? }
</script>
正則表達式(REs)通常被錯誤地認為是只有少數人理解的一種神秘語言。在表面上它們確實看起來雜亂無章,如果你不知道它的語法,那么它的代碼在你眼里只是一堆文字垃圾而已。實際上,正則表達式是非常簡單并且可以被理解。讀完這篇文章后,你將會通曉正則表達式的通用語法。 支持多種平臺 正則表達式最早是由數學家Stephen Kleene于1956年提出,他是在對自然語言的遞增研究成果的基礎上提出來的。具有完整語法的正則表達式使用在字符的格式匹配方面上,后來被應用到熔融信息技術領域。自從那時起,正則表達式經過幾個時期的發展,現在的標準已經被ISO(國際標準組織)批準和被Open Group組織認定。 正則表達式并非一門專用語言,但它可用于在一個文件或字符里查找和替代文本的一種標準。它具有兩種標準:基本的正則表達式(BRE),擴展的正則表達式(ERE)。ERE包括BRE功能和另外其它的概念。 許多程序中都使用了正則表達式,包括xsh,egrep,sed,vi以及在UNIX平臺下的程序。它們可以被很多語言采納,如HTML 和XML,這些采納通常只是整個標準的一個子集。 比你想象的還要普通隨著正則表達式移植到交叉平臺的程序語言的發展,這的功能也日益完整,使用也逐漸廣泛。網絡上的搜索引擎使用它,e-mail程序也使用它,即使你不是一個UNIX程序員,你也可以使用規則語言來簡化你的程序而縮短你的開發時間。 正則表達式101
很多正則表達式的語法看起來很相似,這是因為你以前你沒有研究過它們。通配符是RE的一個結構類型,即重復操作。讓我們先看一看ERE標準的最通用的基本語法類型。為了能夠提供具有特定用途的范例,我將使用幾個不同的程序。 字符匹配
正則表達式的關鍵之處在于確定你要搜索匹配的東西,如果沒有這一概念,Res將毫無用處。
|
Table B: Regular expression repetition operators |
|||
操作 |
解釋 |
例子 |
結果 |
? |
Match any character one time, if it exists |
egrep “?erd” sample.txt |
Will match “berd”, “herd”, etc. and “erd” |
* |
Match declared element multiple times, if it exists |
egrep “n.*rd” sample.txt |
Will match “nerd”, “nrd”, “neard”, etc. |
+ |
Match declared element one or more times |
egrep “[n]+erd” sample.txt |
Will match “nerd”, “nnerd”, etc., but not “erd” |
{n} |
Match declared element exactly n times |
egrep “[a-z]{2}erd” sample.txt |
Will match “cherd”, “blerd”, etc. but not “nerd”, “erd”, “buzzerd”, etc. |
{n,} |
Match declared element at least n times |
egrep “.{2,}erd” sample.txt |
Will match “cherd” and “buzzerd”, but not “nerd” |
{n,N} |
Match declared element at least n times, but not more than N times |
egrep “n[e]{1,2}rd” sample.txt |
Will match “nerd” and “neerd” |
錨是指它所要匹配的格式,如圖C所示。使用它能方便你查找通用字符的合并。例如,我用vi行編輯器命令:s來代表substitute,這一命令的基本語法是:
s/pattern_to_match/pattern_to_substitute/
?
Table C: Regular expression anchors |
|||
操作 |
解釋 |
例子 |
結果 |
^ |
Match at the beginning of a line |
s/^/blah / |
Inserts “blah “ at the beginning of the line |
$ |
Match at the end of a line |
s/$/ blah/ |
Inserts “ blah” at the end of the line |
\< |
Match at the beginning of a word |
s/\</blah/ |
Inserts “blah” at the beginning of the word |
|
|
egrep “\<blah” sample.txt |
Matches “blahfield”, etc. |
\> |
Match at the end of a word |
s/\>/blah/ |
Inserts “blah” at the end of the word |
|
|
egrep “\>blah” sample.txt |
Matches “soupblah”, etc. |
\b |
Match at the beginning or end of a word |
egrep “\bblah” sample.txt |
Matches “blahcake” and “countblah” |
\B |
Match in the middle of a word |
egrep “\Bblah” sample.txt |
Matches “sublahper”, etc. |
Res中的另一可便之處是間隔(或插入)符號。實際上,這一符號相當于一個OR語句并代表|符號。下面的語句返回文件sample.txt中的“nerd” 和 “merd”的句柄:
egrep “(n|m)erd” sample.txt
間隔功能非常強大,特別是當你尋找文件不同拼寫的時候,但你可以在下面的例子得到相同的結果:
egrep “[nm]erd” sample.txt
當你使用間隔功能與Res的高級特性連接在一起時,它的真正用處更能體現出來。
Res的最后一個最重要特性是保留字符(也稱特定字符)。例如,如果你想要查找“ne*rd”和“ni*rd”的字符,格式匹配語句“n[ei]*rd”與“neeeeerd” 和 “nieieierd”相符合,但并不是你要查找的字符。因為‘*’(星號)是個保留字符,你必須用一個反斜線符號來替代它,即:“n[ei]\*rd”。其它的保留字符包括:
一旦你把以上這些字符包括在你的字符搜索中,毫無疑問Res變得非常的難讀。比如說以下的PHP中的eregi搜索引擎代碼就很難讀了。
eregi("^[_a-z0-9-]+(\.[_a-z0-9-]+)*@[a-z0-9-]+(\.[a-z0-9-]+)*$",$sendto)
你可以看到,程序的意圖很難把握。但如果你拋開保留字符,你常常會錯誤地理解代碼的意思。
在本文中,我們揭開了正則表達式的神秘面紗,并列出了ERE標準的通用語法。如果你想閱覽Open Group組織的規則的完整描述,你可以參見: Regular Expressions ,歡迎你在其中的討論區發表你的問題或觀點。
如果我們問那些UNIX系統的愛好者他們最喜歡什么,答案除了穩定的系統和可以遠程啟動之外,十有八九的人會提到正則表達式;如果我們再問他們最頭痛的是什么,可能除了復雜的進程控制和安裝過程之外,還會是正則表達式。那么正則表達式到底是什么?如何才能真正的掌握正則表達式并正確的加以靈活運用?本文將就此展開介紹,希望能夠對那些渴望了解和掌握正則表達式的讀者有所助益。 入門簡介 簡單的說,正則表達式是一種可以用于模式匹配和替換的強有力的工具。我們可以在幾乎所有的基于UNIX系統的工具中找到正則表達式的身影,例如,vi編輯器,Perl或PHP腳本語言,以及awk或sed shell程序等。此外,象JavaScript這種客戶端的腳本語言也提供了對正則表達式的支持。由此可見,正則表達式已經超出了某種語言或某個系統的局限,成為人們廣為接受的概念和功能。 正則表達式可以讓用戶通過使用一系列的特殊字符構建匹配模式,然后把匹配模式與數據文件、程序輸入以及WEB頁面的表單輸入等目標對象進行比較,根據比較對象中是否包含匹配模式,執行相應的程序。 舉例來說,正則表達式的一個最為普遍的應用就是用于驗證用戶在線輸入的郵件地址的格式是否正確。如果通過正則表達式驗證用戶郵件地址的格式正確,用戶所填寫的表單信息將會被正常處理;反之,如果用戶輸入的郵件地址與正則表達的模式不匹配,將會彈出提示信息,要求用戶重新輸入正確的郵件地址。由此可見正則表達式在WEB應用的邏輯判斷中具有舉足輕重的作用。 基本語法 在對正則表達式的功能和作用有了初步的了解之后,我們就來具體看一下正則表達式的語法格式。 正則表達式的形式一般如下: /love/ 其中位于“/”定界符之間的部分就是將要在目標對象中進行匹配的模式。用戶只要把希望查找匹配對象的模式內容放入“/”定界符之間即可。為了能夠使用戶更加靈活的定制模式內容,正則表達式提供了專門的“元字符”。所謂元字符就是指那些在正則表達式中具有特殊意義的專用字符,可以用來規定其前導字符(即位于元字符前面的字符)在目標對象中的出現模式。 較為常用的元字符包括: “+”, “*”,以及 “?”。其中,“+”元字符規定其前導字符必須在目標對象中連續出現一次或多次,“*”元字符規定其前導字符必須在目標對象中出現零次或連續多次,而“?”元字符規定其前導對象必須在目標對象中連續出現零次或一次。 下面,就讓我們來看一下正則表達式元字符的具體應用。 /fo+/ 因為上述正則表達式中包含“+”元字符,表示可以與目標對象中的 “fool”, “fo”, 或者 “football”等在字母f后面連續出現一個或多個字母o的字符串相匹配。 /eg*/ 因為上述正則表達式中包含“*”元字符,表示可以與目標對象中的 “easy”, “ego”, 或者 “egg”等在字母e后面連續出現零個或多個字母g的字符串相匹配。 /Wil?/ 因為上述正則表達式中包含“?”元字符,表示可以與目標對象中的 “Will”, 或者 “Wilson”,等在字母i后面連續出現零個或一個字母l的字符串相匹配。 除了元字符之外,用戶還可以精確指定模式在匹配對象中出現的頻率。例如, /jim{2,6}/ 上述正則表達式規定字符m可以在匹配對象中連續出現2-6次,因此,上述正則表達式可以同jimmy或jimmmmmy等字符串相匹配。 在對如何使用正則表達式有了初步了解之后,我們來看一下其它幾個重要的元字符的使用方式。 s:用于匹配單個空格符,包括tab鍵和換行符; S:用于匹配除單個空格符之外的所有字符; d:用于匹配從0到9的數字; w:用于匹配字母,數字或下劃線字符; W:用于匹配所有與w不匹配的字符; . :用于匹配除換行符之外的所有字符。 (說明:我們可以把s和S以及w和W看作互為逆運算) |
下面,我們就通過實例看一下如何在正則表達式中使用上述元字符。
/s+/
上述正則表達式可以用于匹配目標對象中的一個或多個空格字符。
/d000/
如果我們手中有一份復雜的財務報表,那么我們可以通過上述正則表達式輕而易舉的查找到所有總額達千元的款項。
除了我們以上所介紹的元字符之外,正則表達式中還具有另外一種較為獨特的專用字符,即定位符。定位符用于規定匹配模式在目標對象中的出現位置。
較為常用的定位符包括: “^”, “$”, “” 以及 “B”。其中,“^”定位符規定匹配模式必須出現在目標字符串的開頭,“$”定位符規定匹配模式必須出現在目標對象的結尾,定位符規定匹配模式必須出現在目標字符串的開頭或結尾的兩個邊界之一,而“B”定位符則規定匹配對象必須位于目標字符串的開頭和結尾兩個邊界之內,即匹配對象既不能作為目標字符串的開頭,也不能作為目標字符串的結尾。同樣,我們也可以把“^”和“$”以及“”和“B”看作是互為逆運算的兩組定位符。舉例來說:
/^hell/
因為上述正則表達式中包含“^”定位符,所以可以與目標對象中以 “hell”, “hello”或 “hellhound”開頭的字符串相匹配。
/ar$/
因為上述正則表達式中包含“$”定位符,所以可以與目標對象中以 “car”, “bar”或 “ar” 結尾的字符串相匹配。
/bom/
因為上述正則表達式模式以“”定位符開頭,所以可以與目標對象中以 “bomb”, 或 “bom”開頭的字符串相匹配。
/man/
因為上述正則表達式模式以“”定位符結尾,所以可以與目標對象中以 “human”, “woman”或 “man”結尾的字符串相匹配。
為了能夠方便用戶更加靈活的設定匹配模式,正則表達式允許使用者在匹配模式中指定某一個范圍而不局限于具體的字符。例如:
/[A-Z]/
上述正則表達式將會與從A到Z范圍內任何一個大寫字母相匹配。
/[a-z]/
上述正則表達式將會與從a到z范圍內任何一個小寫字母相匹配。
/[0-9]/
上述正則表達式將會與從0到9范圍內任何一個數字相匹配。
/([a-z][A-Z][0-9])+/
上述正則表達式將會與任何由字母和數字組成的字符串,如 “aB0” 等相匹配。這里需要提醒用戶注意的一點就是可以在正則表達式中使用 “()” 把字符串組合在一起。“()”符號包含的內容必須同時出現在目標對象中。因此,上述正則表達式將無法與諸如 “abc”等的字符串匹配,因為“abc”中的最后一個字符為字母而非數字。
如果我們希望在正則表達式中實現類似編程邏輯中的“或”運算,在多個不同的模式中任選一個進行匹配的話,可以使用管道符 “|”。例如:
/to|too|2/
上述正則表達式將會與目標對象中的 “to”, “too”, 或 “2” 相匹配。
正則表達式中還有一個較為常用的運算符,即否定符 “[^]”。與我們前文所介紹的定位符 “^” 不同,否定符 “[^]”規定目標對象中不能存在模式中所規定的字符串。例如:
/[^A-C]/
上述字符串將會與目標對象中除A,B,和C之外的任何字符相匹配。一般來說,當“^”出現在 “[]”內時就被視做否定運算符;而當“^”位于“[]”之外,或沒有“[]”時,則應當被視做定位符。
最后,當用戶需要在正則表達式的模式中加入元字符,并查找其匹配對象時,可以使用轉義符“”。例如:
/Th*/
上述正則表達式將會與目標對象中的“Th*”而非“The”等相匹配。
使用實例
在對正則表達式有了較為全面的了解之后,我們就來看一下如何在Perl,PHP,以及JavaScript中使用正則表達式。
通常,Perl中正則表達式的使用格式如下:
operator / regular-expression / string-to-replace / modifiers
運算符一項可以是m或s,分別代表匹配運算和替換運算。
其中,正則表達式一項是將要進行匹配或替換操作的模式,可以由任意字符,元字符,或定位符等組成。替換字符串一項是使用s運算符時,對查找到的模式匹配對象進行替換的字符串。最后的參數項用來控制不同的匹配或替換方式。例如:
s/geed/good/
將會在目標對象中查找第一個出現的geed字串,并將其替換為good。如果我們希望在目標對象的全局范圍內執行多次查找—替換操作的話,可以使用參數 “g”,即s/love/lust/g。
此外,如果我們不需要限制匹配的大小寫形式的話,可以使用參數 “i ”。例如,
m/JewEL/i
上述正則表達式將會與目標對象中的jewel,Jewel,或JEWEL相匹配。
在Perl中,使用專門的運算符“=~”指定正則表達式的匹配對象。例如:
$flag =~ s/abc/ABC/
上述正則表達式將會把變量$flag中的字串abc替換為ABC。
下面,我們就在Perl程序中加入正則表達式,驗證用戶郵件地址格式的有效性。代碼如下:
#!/usr/bin/perl
# get input
print “What's your email address? ”;
$email = <>
chomp($email);
# match and display result
if($email =~ /^([a-zA-Z0-9_-])+@([a-zA-Z0-9_-])+(.[a-zA-Z0-9_-])+/)
{
print(“Your email address is correct! ”);
}
else
{
print(“Please try again! ”);
}
如果用戶更偏愛PHP的話,可以使用ereg()函數進行模式匹配操作。ereg()函數的使用格式如下:
ereg(pattern, string)
其中,pattern代表正則表達式的模式,而string則是執行查找替換操作的目標對象。同樣是驗證郵件地址,使用PHP編寫的程序代碼如下:
<?php
if (ereg(“^([a-zA-Z0-9_-])+@([a-zA-Z0-9_-])+(.[a-zA-Z0-9_-])+”,$email))
{ echo “Your email address is correct!”;}
else
{ echo “Please try again!”;}
?>
最后,我們在來看一下JavaScript。JavaScript 1.2中帶有一個功能強大的RegExp()對象,可以用來進行正則表達式的匹配操作。其中的test()方法可以檢驗目標對象中是否包含匹配模式,并相應的返回true或false。
我們可以使用JavaScript編寫以下腳本,驗證用戶輸入的郵件地址的有效性。
<html>
<head>
< language="Javascript1.2">
<!-- start hiding
function verifyAddress(obj)
{
var email = obj.email.value;
var pattern = /^([a-zA-Z0-9_-])+@([a-zA-Z0-9_-])+(.[a-zA-Z0-9_-])+/;
flag = pattern.test(email);
if(flag)
{
alert(“Your email address is correct!”);
return true;
}
else
{
alert(“Please try again!”);
return false;
}
}
// stop hiding -->
</script>
</head>
<body>
<form onSubmit="return verifyAddress(this);">
<input name="email" type="text">
<input type="submit" value="提交">
</form>
</body>
</html>
原著:Steve Mansour
sman@scruznet.com
Revised: June 5, 1999
(copied by jm /at/ jmason.org from http://www.scruz.net/%7esman/regexp.htm, after the original disappeared! )
翻譯:Neo Lee
neo.lee@gmail.com
2004年10月16日
譯者按:原文因為年代久遠,文中很多鏈接早已過期(主要是關于vi、sed等工具的介紹和手冊),本譯文中已將此類鏈接刪除,如需檢查這些鏈接可以查看上面鏈接的原文。除此之外基本照原文直譯,括號中有“譯者按”的部分是譯者補充的說明。如有內容方面的問題請直接和Steve Mansor聯系,當然,如果你只寫中文,也可以和我聯系。
什么是正則表達式
范例
?? 簡單
?? 中級(神奇的咒語)
?? 困難(不可思議的象形文字)
不同工具中的正則表達式
我們將在如下的章節中利用一些例子來解釋正則表達式的用法,絕大部分的例子是基于vi中的文本替換命令和grep文件搜索命令來書寫的,不過它們都是比較典型的例子,其中的概念可以在sed、awk、perl和其他支持正則表達式的編程語言中使用。你可以看看不同工具中的正則表達式這一節,其中有一些在別的工具中使用正則表達式的例子。還有一個關于vi中文本替換命令(s)的簡單說明附在文后供參考。
在最簡單的情況下,一個正則表達式看上去就是一個普通的查找串。例如,正則表達式"testing"中沒有包含任何元字符,,它可以匹配"testing"和"123testing"等字符串,但是不能匹配"Testing"。
要想真正的用好正則表達式,正確的理解元字符是最重要的事情。下表列出了所有的元字符和對它們的一個簡短的描述。
元字符 | ? | 描述 |
---|---|---|
匹配任何單個字符。例如正則表達式r.t匹配這些字符串:rat、rut、r t,但是不匹配root。? | ||
匹配行結束符。例如正則表達式weasel$ 能夠匹配字符串"He's a weasel"的末尾,但是不能匹配字符串"They are a bunch of weasels."。? | ||
匹配一行的開始。例如正則表達式^When in能夠匹配字符串"When in the course of human events"的開始,但是不能匹配"What and When in the"。 | ||
匹配0或多個正好在它之前的那個字符。例如正則表達式.*意味著能夠匹配任意數量的任何字符。 | ||
這是引用府,用來將這里列出的這些元字符當作普通的字符來進行匹配。例如正則表達式\$被用來匹配美元符號,而不是行尾,類似的,正則表達式\.用來匹配點字符,而不是任何字符的通配符。 | ||
[c1-c2] [^c1-c2] | 匹配括號中的任何一個字符。例如正則表達式r[aou]t匹配rat、rot和rut,但是不匹配ret。可以在括號中使用連字符-來指定字符的區間,例如正則表達式[0-9]可以匹配任何數字字符;還可以制定多個區間,例如正則表達式[A-Za-z]可以匹配任何大小寫字母。另一個重要的用法是“排除”,要想匹配除了指定區間之外的字符——也就是所謂的補集——在左邊的括號和第一個字符之間使用^字符,例如正則表達式[^269A-Z] 將匹配除了2、6、9和所有大寫字母之外的任何字符。 | |
匹配詞(word)的開始(\<)和結束(\>)。例如正則表達式\<the能夠匹配字符串"for the wise"中的"the",但是不能匹配字符串"otherwise"中的"the"。注意:這個元字符不是所有的軟件都支持的。 | ||
將 \( 和 \) 之間的表達式定義為“組”(group),并且將匹配這個表達式的字符保存到一個臨時區域(一個正則表達式中最多可以保存9個),它們可以用 \1 到\9 的符號來引用。 | ||
將兩個匹配條件進行邏輯“或”(Or)運算。例如正則表達式(him|her) 匹配"it belongs to him"和"it belongs to her",但是不能匹配"it belongs to them."。注意:這個元字符不是所有的軟件都支持的。 | ||
匹配1或多個正好在它之前的那個字符。例如正則表達式9+匹配9、99、999等。注意:這個元字符不是所有的軟件都支持的。 | ||
匹配0或1個正好在它之前的那個字符。注意:這個元字符不是所有的軟件都支持的。 | ||
\{i,j\} | 匹配指定數目的字符,這些字符是在它之前的表達式定義的。例如正則表達式A[0-9]\{3\} 能夠匹配字符"A"后面跟著正好3個數字字符的串,例如A123、A348等,但是不匹配A1234。而正則表達式[0-9]\{4,6\} 匹配連續的任意4個、5個或者6個數字字符。注意:這個元字符不是所有的軟件都支持的。 |
最簡單的元字符是點,它能夠匹配任何單個字符(注意不包括新行符)。假定有個文件test.txt包含以下幾行內容:
要想匹配行首的字符要使用抑揚字符(^)——又是也被叫做插入符。例如,想找到text.txt中行首"he"打頭的行,你可能會先用簡單表達式he,但是這會匹配第三行的the,所以要使用正則表達式^he,它只匹配在行首出現的h。
有時候指定“除了×××都匹配”會比較容易達到目的,當抑揚字符(^)出現在方括號中是,它表示“排除”,例如要匹配he ,但是排除前面是t or s的情性(也就是the和she),可以使用:[^st]he。
可以使用方括號來指定多個字符區間。例如正則表達式[A-Za-z]匹配任何字母,包括大寫和小寫的;正則表達式[A-Za-z][A-Za-z]* 匹配一個字母后面接著0或者多個字母(大寫或者小寫)。當然我們也可以用元字符+做到同樣的事情,也就是:[A-Za-z]+ ,和[A-Za-z][A-Za-z]*完全等價。但是要注意元字符+ 并不是所有支持正則表達式的程序都支持的。關于這一點可以參考后面的正則表達式語法支持情況。
要指定特定數量的匹配,要使用大括號(注意必須使用反斜杠來轉義)。想匹配所有100和1000的實例而排除10和10000,可以使用:10\{2,3\},這個正則表達式匹配數字1后面跟著2或者3個0的模式。在這個元字符的使用中一個有用的變化是忽略第二個數字,例如正則表達式0\{3,\} 將匹配至少3個連續的0。
這里有一些有代表性的、比較簡單的例子。
vi 命令 | 作用 |
:%s/ */ /g | 把一個或者多個空格替換為一個空格。 |
:%s/ *$// | 去掉行尾的所有空格。 |
:%s/^/ / | 在每一行頭上加入一個空格。 |
:%s/^[0-9][0-9]* // | 去掉行首的所有數字字符。 |
:%s/b[aeio]g/bug/g | 將所有的bag、beg、big和bog改為bug。? |
:%s/t\([aou]\)g/h\1t/g | 將所有tag、tog和tug分別改為hat、hot和hug(注意用group的用法和使用\1引用前面被匹配的字符)。 |
將所有方法foo(a,b,c)的實例改為foo(b,a,c)。這里a、b和c可以是任何提供給方法foo()的參數。也就是說我們要實現這樣的轉換:
之前 | ? | 之后 |
foo(10,7,2) | foo(7,10,2) | |
foo(x+13,y-2,10) | foo(y-2,x+13,10) | |
foo( bar(8), x+y+z, 5) | foo( x+y+z, bar(8), 5) |
下面這條替換命令能夠實現這一魔法:
現在讓我們把它打散來加以分析。寫出這個表達式的基本思路是找出foo()和它的括號中的三個參數的位置。第一個參數是用這個表達式來識別的::\([^,]*\),我們可以從里向外來分析它:?
[^,] | ? | 除了逗號之外的任何字符 |
[^,]* | 0或者多個非逗號字符 | |
\([^,]*\) | 將這些非逗號字符標記為\1,這樣可以在之后的替換模式表達式中引用它 | |
\([^,]*\), | 我們必須找到0或者多個非逗號字符后面跟著一個逗號,并且非逗號字符那部分要標記出來以備后用。 |
現在正是指出一個使用正則表達式常見錯誤的最佳時機。為什么我們要使用[^,]*這樣的一個表達式,而不是更加簡單直接的寫法,例如:.*,來匹配第一個參數呢?設想我們使用模式.*來匹配字符串"10,7,2",它應該匹配"10,"還是"10,7,"?為了解決這個兩義性(ambiguity),正則表達式規定一律按照最長的串來,在上面的例子中就是"10,7,",顯然這樣就找出了兩個參數而不是我們期望的一個。所以,我們要使用[^,]*來強制取出第一個逗號之前的部分。
這個表達式我們已經分析到了:foo(\([^,]*\),這一段可以簡單的翻譯為“當你找到foo(就把其后直到第一個逗號之前的部分標記為\1”。然后我們使用同樣的辦法標記第二個參數為\2。對第三個參數的標記方法也是一樣,只是我們要搜索所有的字符直到右括號。我們并沒有必要去搜索第三個參數,因為我們不需要調整它的位置,但是這樣的模式能夠保證我們只去替換那些有三個參數的foo()方法調用,在foo()是一個重載(overoading)方法時這種明確的模式往往是比較保險的。然后,在替換部分,我們找到foo()的對應實例,然后利用標記好的部分進行替換,是的第一和第二個參數交換位置。
這里有幾行我們現在的數據:
下面就是第一個替換命令:
下面這個替換命令則用來去除空格:
Billy tried really hard而你想把"really"、"really really",以及任意數量連續出現的"really"字符串換成一個簡單的"very"(simple is good!),那么以下命令:
Sally tried really really hard
Timmy tried really really really hard
Johnny tried really really really really hard
:%s/\(really \)\(really \)*/very /就會把上述的文本變成:
Billy tried very hard表達式\(really \)*匹配0或多個連續的"really "(注意結尾有個空格),而\(really \)\(really \)* 匹配1個或多個連續的"really "實例。
Sally tried very hard
Timmy tried very hard
Johnny tried very hard
當然,你也可以在Visual C++編輯器中使用RE。選擇Edit->Replace,然后選擇"Regular expression"選擇框,Find What輸入框對應上面介紹的vi命令:%s/pat1/pat2/g中的pat1部分,而Replace輸入框對應pat2部分。但是,為了得到vi的執行范圍和g選項,你要使用Replace All或者適當的手工Find Next and Replace(譯者按:知道為啥有人罵微軟弱智了吧,雖然VC中可以選中一個范圍的文本,然后在其中執行替換,但是總之不夠vi那么靈活和典雅)。
Sed是Stream EDitor的縮寫,是Unix下常用的基于文件和管道的編輯工具,可以在手冊中得到關于sed的詳細信息。
這里是一些有趣的sed腳本,假定我們正在處理一個叫做price.txt的文件。注意這些編輯并不會改變源文件,sed只是處理源文件的每一行并把結果顯示在標準輸出中(當然很容易使用重定向來定制):
sed腳本 | ? | 描述 |
sed 's/^$/d' price.txt | 刪除所有空行 | |
sed 's/^[ \t]*$/d' price.txt | 刪除所有只包含空格或者制表符的行 | |
sed 's/"http://g' price.txt | 刪除所有引號 |
在Aho,Weinberger和Kernighan的書The AWK Programming Language中有很多很好的awk的例子,請不要讓下面這些微不足道的腳本例子限制你對awk強大能力的理解。我們同樣假定我們針對price.txt文件進行處理,跟sed一樣,awk也只是把結果顯示在終端上。?
awk腳本 | ? | 描述 |
awk '$0 !~ /^$/' price.txt | 刪除所有空行 | |
awk 'NF > 0' price.txt | awk中一個更好的刪除所有行的辦法 | |
awk '$2 ~ /^[JT]/ {print $3}' price.txt | 打印所有第二個字段是'J'或者'T'打頭的行中的第三個字段 | |
awk '$2 !~ /[Mm]isc/ {print $3 + $4}' price.txt | 針對所有第二個字段不包含'Misc'或者'misc'的行,打印第3和第4列的和(假定為數字) | |
awk '$3 !~ /^[0-9]+\.[0-9]*$/ {print $0}' price.txt | 打印所有第三個字段不是數字的行,這里數字是指d.d或者d這樣的形式,其中d是0到9的任何數字 | |
awk '$2 ~ /John|Fred/ {print $0}' price.txt | 如果第二個字段包含'John'或者'Fred'則打印整行 |
下面的例子中我們假定在文件phone.txt中包含以下的文本,——其格式是姓加一個逗號,然后是名,然后是一個制表符,然后是電話號碼:
Francis, John?????????? 5-3871
Wong, Fred????????????? 4-4123
Jones, Thomas?????????? 1-4122
Salazar, Richard??????? 5-2522
grep命令 | ? | 描述 |
grep '\t5-...1' phone.txt | 把所有電話號碼以5開頭以1結束的行打印出來,注意制表符是用\t表示的 | |
grep '^S[^ ]* R' phone.txt | 打印所有姓以S打頭和名以R打頭的行 | |
grep '^[JW]' phone.txt | 打印所有姓開頭是J或者W的行 | |
grep ', ....\t' phone.txt | 打印所有姓是4個字符的行,注意制表符是用\t表示的 | |
grep -v '^[JW]' phone.txt | 打印所有不以J或者W開頭的行 | |
grep '^[M-Z]' phone.txt | 打印所有姓的開頭是M到Z之間任一字符的行 | |
grep '^[M-Z].*[12]' phone.txt | 打印所有姓的開頭是M到Z之間任一字符,并且點號號碼結尾是1或者2的行 |
egrep command | ? | Description |
egrep '(John|Fred)' phone.txt | 打印所有包含名字John或者Fred的行 | |
egrep 'John|22$|^W' phone.txt | 打印所有包含John 或者以22結束或者以W的行 | |
egrep 'net(work)?s' report.txt | 從report.txt中找到所有包含networks或者nets的行 |
命令或環境 | . | [ ] | ^ | $ | \( \) | \{ \} | ? | + | | | ( ) |
vi | ?X? | ?X? | ?X? | ?X? | ?X? | ? | ? | ? | ? | ? |
Visual C++ | ?X? | ?X? | ?X? | ?X? | ?X? | ? | ? | ? | ? | ? |
awk | ?X? | ?X? | ?X? | ?X? | ? | ? | ?X? | ?X? | ?X? | ?X? |
sed | ?X? | ?X? | ?X? | ?X? | ?X? | ?X? | ? | ? | ? | ? |
Tcl | ?X? | ?X? | ?X? | ?X? | ?X? | ? | ?X? | ?X? | ?X? | ?X? |
ex | ?X? | ?X? | ?X? | ?X? | ?X? | ?X? | ? | ? | ? | ? |
grep | ?X? | ?X? | ?X? | ?X? | ?X? | ?X? | ? | ? | ? | ? |
egrep | ?X? | ?X | ?X? | ?X? | ?X? | ? | ?X? | ?X? | ?X? | ?X? |
fgrep | ?X? | ?X? | ?X? | ?X? | ?X? | ? | ? | ? | ? | ? |
perl | ?X | ?X | ?X | ?X | ?X | ? | ?X | ?X | ?X | ?X |
?
s 表示其后是一個替換命令。
pat1 這是要查找的一個正則表達式,這篇文章中有一大堆例子。
g 可選標志,帶這個標志表示替換將針對行中每個匹配的串進行,否則則只替換行中第一個匹配串。
?????? 正則表達式(regular expression)對象包含一個正則表達式模式(pattern)。它具有用正則表達式模式去匹配或代替一個串(string)中特定字符(或字符集合)的屬性(properties)和方法(methods)。 要為一個單獨的正則表達式添加屬性,可以使用正則表達式構造函數(constructor function),無論何時被調用的預設置的正則表達式擁有靜態的屬性(the predefined RegExp object has static properties that are set whenever any regular expression is used, 我不知道我翻得對不對,將原文列出,請自行翻譯)。
[注意] 文本格式的參數不用引號,而在用構造函數時的參數需要引號。如:/ab+c/i new RegExp("ab+c","i")是實現一樣的功能。在構造函數中,一些特殊字符需要進行轉意(在特殊字符前加"\")。如:re = new RegExp("\\w+")
正則表達式中的特殊字符
|
說了這么多了,我們來看一些正則表達式的實際應用的例子:
E-mail地址驗證:
正則表達式對象的屬性及方法
?function test_email(strEmail) {
??var myReg = /^[_a-z0-9]+@([_a-z0-9]+\.)+[a-z0-9]{2,3}$/;
??if(myReg.test(strEmail)) return true;
??return false;
?}
HTML代碼的屏蔽
?function mask_HTMLCode(strInput) {
?? var myReg = /<(\w+)>/;
?? return strInput.replace(myReg, "<$1>");
?}
預定義的正則表達式擁有有以下靜態屬性:input, multiline, lastMatch, lastParen, leftContext, rightContext和$1到$9。其中input和multiline可以預設置。其他屬性的值在執行過exec或test方法后被根據不同條件賦以不同的值。許多屬性同時擁有長和短(perl風格)的兩個名字,并且,這兩個名字指向同一個值。(JavaScript模擬perl的正則表達式)
正則表達式對象的屬性
屬性 含義 $1...$9 如果它(們)存在,是匹配到的子串 $_ 參見input $* 參見multiline $& 參見lastMatch $+ 參見lastParen $` 參見leftContext $’ 參見rightContext constructor 創建一個對象的一個特殊的函數原型 global 是否在整個串中匹配(bool型) ignoreCase 匹配時是否忽略大小寫(bool型) input 被匹配的串 lastIndex 最后一次匹配的索引 lastParen 最后一個括號括起來的子串 leftContext 最近一次匹配以左的子串 multiline 是否進行多行匹配(bool型) prototype 允許附加屬性給對象 rightContext 最近一次匹配以右的子串 source 正則表達式模式 lastIndex 最后一次匹配的索引
正則表達式對象的方法
方法 含義 compile 正則表達式比較 exec 執行查找 test 進行匹配 toSource 返回特定對象的定義(literal representing),其值可用來創建一個新的對象。重載Object.toSource方法得到的。 toString 返回特定對象的串。重載Object.toString方法得到的。 valueOf 返回特定對象的原始值。重載Object.valueOf方法得到
例子
<script language = "JavaScript">
var myReg = /(\w+)\s(\w+)/;
var str? = "John Smith";
var newstr = str.replace(myReg, "$2, $1");
document.write(newstr);
</script>
將輸出"Smith, John"
| |||||||||
日 | 一 | 二 | 三 | 四 | 五 | 六 | |||
---|---|---|---|---|---|---|---|---|---|
27 | 28 | 29 | 30 | 1 | 2 | 3 | |||
4 | 5 | 6 | 7 | 8 | 9 | 10 | |||
11 | 12 | 13 | 14 | 15 | 16 | 17 | |||
18 | 19 | 20 | 21 | 22 | 23 | 24 | |||
25 | 26 | 27 | 28 | 29 | 30 | 31 | |||
1 | 2 | 3 | 4 | 5 | 6 | 7 |