1) JavaScript 中的Regex
JavaScript用RegExp的對象表示Regex。
2) 建立JavaScriptRegex
a) re = new RegExp("a*b") // 使用字串作為參數,而不是literals
b) re = /a*b/
上面2中方式都是建立一個Regex,/a*b/ 叫做Regex的字面值(literals)。
3) 瞭解Regex
a. 什麼是Regex
JavaScriptRegex是PerlRegex的子集。
Regex是一個用於匹配的模板(關於Regex,有很多不同的定義)。比如 /abc/ 就是用於匹配含有abc的所有的字串。
b. Regex的組成
Regex是由一系列的字元組成,比如 /abc/。具體來說包括:字母字元,數字字元,逸出字元,標點(punctuation)字元。下面列舉一些常用的Regex字元:
1. 數字字元和字母字元匹配該字元本身,比如說 /javascript/ 就是匹配含有javascript的字串
2. \t 匹配 Tab(定位字元)
3. \n 匹配 newline(換行)
4. \r 匹配斷行符號
5. \s 匹配Null 字元
6. \S 匹配非Null 字元
7. \b 匹配字(word)邊界,比如 /\bjavascript\b/ 匹配的字串裡,必須含有字javascript,而類似 123javascript22,這類的字串無法與之匹配,注意,字邊界中字是由數字,字母或底線組成。
8. \B 匹配非字邊界
9. ^ $ . * + ? = ! : | \ / ( ) [ ] { }
引用內容上面^ $ . * + ? = ! : | \ / ( ) [ ] { }屬於標點字元("和@不在其中),他們在Regex中有特殊的含義,假如我們要匹配 "abc?abc" 這個字串的時候,就有問題了,因為 ? 是有特殊意義的,所以他們需要轉義,也就是用 \? 來代替?,也就是,要用/abc\?abc/ 這個Regex來匹配上面的字串,而不能用/abc?abc/。因為 " 沒有特殊意義,所以我們使用的時候不需要轉義,但是假如你轉義了 \" ,也不會影響結果, \" 和 "是等效的,即對沒有特殊意義的字元進行轉義的結果和沒轉義一樣。通常我們不去記JavaScript中用到了那些標點字元,只要是標點字元,如果不用特殊意義,我們就轉義。
由於標點字元比較複雜,所以專門拿出來,再下面講。
c. 標點字元的意義
1. 字元類,用標點字元[],例如:[abc]。注意字元類只能匹配長度為1的字元,這也是它為什麼叫字元類的原因了。
[abc]可以匹配 a , b 或者 c。
[^abc]可以匹配非a,b,c的所有的字元。
[a-z0-9]表示a到z的所有字元和0-9的所有字元。也就是對於英文字元和數字字元可以使用"-"表示一個連續的集合。
. 點號,它可以表示所有的字元,除了換行之外。
\w,匹配所有的數字字元和字母字元以及"_",它等價於[0-9a-zA-Z_]
\W,大寫的W,匹配所有的字元,不包括數字字元,字母字元,以及"_",它等價於[^0-9a-zA-Z_]
\d,所有數字,它等價於[0-9]
\D,所有非數字,它等價於[^0-9]
[\b],表示退格,注意,不加[],表示字(word)邊界。
2. 重複
*,表示前面的字元出現0次或0次以上
+,表示前面的字元出現1次或1次以上
?,表示前面的字元出現0次或1次
{n,m},前面的字元重複次數在 n 到 m 次之間(n<=x<=m)
{n,},前面的字元重複次數大於等於n(x>=n)
{n},前面的字元重複的次數等於n(x==n)
3. 重複字元
處於上面符號之前的字元,叫重複字元。
4. 一些例子:
/a*/ 匹配 "aaa"
/a*/ 也匹配 "bbb",因為*表示重複0次或多次,因此會使得他們匹配,這應該注意,/a*/可以和任何字串匹配。
5. 貪婪的重複(匹配)和非貪婪的重複(匹配)
/a*b/ 匹配 "aaaab"。我們說過a*可以匹配Null 字元串,也可以匹配 a 或者 aa ,aaa,aaaa,那這裡到底是匹配什麼呢?實際上,匹配過程一直繼續下去,到第4個a,也就是這裡的 a* 匹配到了 aaaa,匹配方式是貪婪的。也就是:儘可能多的讓重複字元重複匹配。
在*,?,+,{n,m},{n,},{n}後面加上?就表示進行非貪婪的重複。所謂非貪婪的重複,就是說:重複字元僅進行一次成功匹配。但是,Regex還有一個必須准尋一個準則------Regex匹配完成的標誌是,在被匹配的字串中找到第一個可以匹配的位置或者並不存在與之匹配的串,匹配的過程是從被匹配串的第一個字母開始,一個一個繼續下去的,當以第一個字母開始的子串無法被匹配的時候,才開始以第二字母為開始字母進行匹配。這句話之所以標記為紅色,因為它十分重要,正確理解這句話,不僅對下面的分析有益,而且還是以後使用JavaScript RegExp對象的基礎。我們來看看這個運算式:
/a*?b/ 明顯,他匹配的是 "b",我們前面已經講過非貪婪的重複是重複字元僅進行一次成功匹配,也就是 a*? 匹配空串,結果就是匹配 "b",雖然到目前為止還沒有設計到程式設計,但是為了驗證這個問題,這裡給出一個代碼: 程式碼function f(regexp,str){
return str.search(regexp)
}
document.write(f(/a/,"b")+"<br />")
document.write(f(/a*?b/,"b")+"<br />")
document.write(f(/a*?b/,"aaab")+"<br />") 引用內容結果顯示
-1
0
0
這也就是說, /a*?b/ 能匹配 "b",同時,/a*?b/ 也能匹配 "aaab"。這不就和 /a*b/的匹配結果一樣嗎?其實因為 a*? 第一次成功匹配之後,發現無法找到一個可以和Regex匹配的串,於是繼續匹配,一直到找到了第一個可以匹配的串 "aaab"才結束。
7. 選擇(Alternation),分組(Grouping),引用(References)
|,選擇,匹配該符號左邊或者是右邊的子運算式,比如 /java|script/ 可以匹配"java"也可以匹配“script”,注意,選擇匹配只要左邊匹配成功的就不會再進行右邊的匹配了。
(),組合,把括弧類的運算式看成一個獨立的單元,使之可以使用*,+,?,|等等,主要的組合可可以被引用;(?:),也是組合的一種形式,但是這樣的組合不能被引用。
\1,\2等,表示引用,\後的數字為組號。組號是從左至右分配的,也就是最左邊的一個括弧開始是第一組,這樣分配下去。\n將匹配第n組在第一次匹配成功的字串。比如:
/(a*b)\1/ 可以匹配 aabaab,但不能匹配 aabab。更加複雜一些的情況:
/(abc(de))\1\2/ 匹配 "abcdeabcdede"。另外不能在[]中使用引用,例如 /(a*b)[\1]/ 非法
8. ^和$,^匹配字串的開始或者是一行的開始(在多行模式下),$匹配字串的結束或者是一行的結束(在多行模式下),例如:
/a*b/ 匹配 "aaabaab"
/^a*b$/ 不匹配 "aaabaab"
9.標誌(Flags)
標誌相對前面來說是一個簡單的知識點,假如我們希望匹配含有 javascript 或者 JavaScript 的字串,我們可以使用 /[jJ]ava[sS]cript/ ,還有一種方法,就是使用標誌,即 /javascript/i ,i表示進行大小寫不敏感的匹配。另外還有2個標誌,g,m。
g表示進行全域匹配,也就是找出所有可以匹配的串,而不會因為找到一個就停止下來。
m多行模式,影響^,$的匹配,使^匹配每行的開始,$匹配每行的結束。
這3個標誌可以一起使用,也可以單獨使用,比如 /abc/gi /abc/mi /abc/gmi
4) 在 JavaScript 中使用Regex
從理論走到實踐是一個艱苦的過程,終於可以開始讓人興奮的應用了。
再論構建 RegExp對象,我們可以通過Regex字面值(literals)來構建一個RegExp對象:
re = /\bjava\b/
同樣可以使用建構函式 re = new RegExp("\\bjava\\b");,可以看到不同,首先傳遞的字串不需要 "/",其次,裡面的 \ 需要轉義。這是可以理解的,因為如果沒有了來轉義,結果就是"\bjava\b",而 \b 在字串裡面是退格符。
a. String中的方法
1.search(),接受一個String或者是一個RegExp對象,假如是String則先調用RegExp的建構函式,轉化成為RegExp對象。方法返回字串中第一次匹配成功的位置,因此g標誌就沒有含義了。例如: 程式碼re = /killercat/i
str = "I am Killercat"
document.write(str.search(re))
結果:5
2.replace(),有2個參數,第一個為Regex或字串,第二個為要替換的字串。例如: 程式碼re = /killercat/ig
str = "I am Killercat killercat"
document.write(str.replace(re,"cat")+"<br />")
document.write(str)
結果:
I am cat cat
I am Killercat killercat
解析:
1) 假如第一個參數為字串,不會轉化成為Regex,而是尋找這個字串。
2) 不會改變原字串的值,而是返回一個新的字串
3) 可以使用g,進行全域匹配
3. match(),參數和search一樣,可以是字串也可以是RegExp對象,String會被轉化成為RegExp對象,但是match支援g標誌,同時match返回一個數組,例如:(注意,本結果是在firefox2.0下得到的) 程式碼re1 = /a*?b/g
re2 = /a*b/g
str = "aaabaab"
arr = str.match(re1)
for(ele in arr){
document.write(arr[ele]+"<br />")
}
document.write("next...<br />");
arr = str.match(re2)
for(ele in arr){
document.write(arr[ele]+"<br />")
}
結果:
aaab
aab
next...
aaab
aab
4. split(),參數為一個字串或者一個Regex,這個參數作為字串的分割符,返回分割的子串組成的數組,例如: 程式碼re1 = /\s+/
str = "123 456 789"
arr = str.split(" ");
for(var ele in arr){
document.write(arr[ele]+"<br />")
}
document.write("next...<br />");
str = "123 456 789"
arr = str.split(re1);
for(ele in arr){
document.write(arr[ele]+"<br />")
}
結果:
123
456
789
next...
123
456
789
b. RegExp對象的方法
1. test(),參數是一個字串,出現一次匹配則返回true,否則為false 程式碼re = /a*?b/
str = "aaabaab"
document.write(re.test(str));
結果為:true