一、創建一個正則表達式
1 字面量方式:
var expression = /pattern/flags
其中的pattern可以是任何簡單的或者復雜的正則表達式,可以包含字符類、限定符、分組、向前查找以及反向引用。每個正則表達式都可帶有一個或者多個flags.
正則表達式的匹配模式支持下列3個標志:
- g:表示全局模式,即模式將被應用于所有字符串,而非在發現第一個匹配項時立即停止
例如:
var regex = /b/;
var str = 'abba';
regex.test(str); // true
regex.test(str); // true
regex.test(str); // true
var regex = /b/g;
var str = 'abba';
regex.test(str); // true
regex.test(str); // true
regex.test(str); // false
- i:表示不區分大小寫模式,即在確定匹配項時忽略模式與字符串的大小寫
例如:
/*匹配第一個"bat"或"cat",不區分大小寫*/
var pattern2 = /[bc]at/i/
- m:表示多行模式,即在到達一行文本末尾時還會繼續查找下一行中是否存在于模式匹配的項;會修改
^
和$
的行為。默認情況下(即不加m
修飾符時),^
和$
匹配字符串的開始處和結尾處,加上m
修飾符以后,^
和$
還會匹配行首和行尾,即^
和$
會識別換行符(\n
)
例如:
/world$/.test('hello world\n') // false
/world$/m.test('hello world\n') // true
注:模式中使用的所有元字符都必須轉義。正則表達式中的元字符包括:
( [ { \ ^ $ | ) ? * + . ] }
這些元字符在正則表達式中都有一種或多種特殊用途,因此如果想要匹配字符串中包含的這些字符,就必須對他們進行轉義
例如:
/*匹配第一個"bat"或"cat",不區分大小寫*/
var pattern = /[bc]at/i
/*匹配第一個[bc]at,不區分大小寫*/
var pattern = /\[bc\]at/i
2 調用RegExp對象的構造函數
var re = new RegExp("patern","flags")
例如:
字面量方式:
/*匹配第一個"bat"或者"cat",不區分大小寫*/
var pattern = /[bc]at/i
構造函數方式:
/*匹配第一個"bat"或者"cat",不區分大小寫*/
var pattern = new RegExp("[bc]at","i");
注:傳遞給RegExp構造函數的兩個參數都是字符串(不能把正則表達式字面量傳遞給RegExp構造函數)。由于RegExp構造函數模式參數是字符串,所以在某些情況下要對字符進行雙重轉義。(例如:字符\在字符串中通常被轉義為\,而在正則表達式字符串中就會變成\\)
例如:
字面量模式:
/\[bc\]at/
等價的字符串:
"\\[bc]at"
字面量模式:
/\w\\hello\\123/
等價的字符串:
"\\w\\\\hello\\\\123"
3 兩種方法的區別:
第一種方法在編譯時新建正則表達式,第二種方法在運行時新建正則表達式。考慮到書寫的便利和直觀,實際應用中,基本上都采用字面量的寫法。
二、正則對象的屬性和方法
1 屬性
正則對象的屬性分成兩類。
一類是修飾符相關,返回一個布爾值,表示對應的修飾符是否設置
- ignoreCase:返回一個布爾值,表示是否設置了i修飾符,該屬性只讀
- global:返回一個布爾值,表示是否設置了g修飾符,該屬性只讀
- multiline:返回一個布爾值,表示是否設置了m修飾符,該屬性只讀
例子:
var r = /abc/igm
r.ignoreCase //true
r.global //true
r.mutiline //true
另一類是與修飾符無關的屬性
- lastIndex:表示開始搜索下一個匹配項的字符的位置,從0算起;該屬性可讀寫,只有在設置了g時才有意義
- source:返回正則表達式的字符串形式,只讀
var r = /abc/igm
r.lastIndex //0
r.source //"abc"
var r = new RegExp("abc","igm")
r.lastIndex //0
r.source //"abc"
注:盡管第一個模式使用的是字面量,第二個使用的構造函數模式,但是source屬性相同。可見,source保存的是字面量形式的字符串
2 方法(此方法屬于正則對象;即pattern.方法()。注意區別于下面介紹的字符串對象的方法)
-
test()
返回一個布爾值,表示當前模式是否能匹配參數字符串
pattern.test("字符串")
/cat/.test("vat and dogs") //true
如果正則表達式帶有g
修飾符,則每一次test
方法都從上一次結束位置的后一位向后匹配
var r = /x/g
var s = '_x_x'
console.log(r.lastIndex); //0
console.log(r.test(s)); //true
console.log(r.lastIndex); //2
console.log(r.test(s)); //true
console.log(r.lastIndex); //4
console.log(r.test(s)); //false
注:如果正則模式是一個空字符串,則匹配所有字符串
new RegExp("").test("abc")
這里不能使用字面量形式,否則會報錯!!!
-
exec()
方法可以返回匹配結果,如果發現匹配,就返回一個數組,成員是每一個匹配成功的字符串,否則返回null
pattern.exec("字符串")
var s = '_x_x'
var r1 = /x/
var r2 = /y/
console.log(r1.exec(s)); // ['x']
console.log(r2.exec(s)) //null
如果pattern包含分組(即含有圓括號:"()",用來一次匹配多個字符),則返回的數組包含多個成員,第一項是匹配的整個字符串,第二項是第一個分組,第三項是第二個分組,以此類推;真個數組的length
屬性等于分組的數量+1
var r = /a(b+)a/;
var arr = r.exec('_abbba_aba_');
arr // ["abbba", "bbb"]
arr.index // 1
arr.input // "_abbba_aba_"
input:整個原字符串
index:pattern匹配成功的開始位置(從0開始)
以上兩個屬性是返回的數組所擁有
注:如果正則模式是一個空字符串,則exec
方法返回一個空數組
var r1 = new RegExp('');
var a1 = r1.exec('abc');
console.log(a1); //["", index: 0, input: "abc"]
console.log(a1.index); //0
console.log(r1.lastIndex); //0
var r1 = new RegExp('()');
var a1 = r1.exec('abc');
console.log(a1); //["", "", index: 0, input: "abc"]
console.log(a1.index); //0
console.log(r1.lastIndex); //0
三、字符串的模式匹配方法(字符串.方法(pattern) )
-
match()
:返回一個數組,成員是所有匹配的子字符串,match
和exec
類似,匹配成功則返回一個數組,否則返回null
注意:兩個方法在沒有g
標識符的情況下表現相同(即返回匹配的真個字符串,以及匹配到的分組);在有g
的情況下,match
不會返回分組,而exec
會返回分組,并且lastIndex
屬性對match無效
沒有g標識符:
var s = 'abba';
var r = /a(b+?)/;
console.log(s.match(r)) // ["ab", "b", index: 0, input: "abba"]
console.log(r.exec(s)) // ["ab", "b", index: 0, input: "abba"]
有g標識符:
var s = 'abba';
var r = /a(b+?)/g;
console.log(s.match(r)) // ["ab"] ,不包括分組,并且沒有Index和input屬性
console.log(r.exec(s)) // ["ab", "b", index: 0, input: "abba"]
因此,exec
比match
更強大
設置正則表達式的·lastIndex·屬性,對match
方法無效,匹配總是從字符串第一個開始
var r = /a|b/g
r.lastIndex =7;
console.log('xaxb'.match(r)); //["a","b"]
console.log(r.lastIndex); //0
-
search
方法,返回第一個滿足條件的匹配結果在原字符串中的位置,如果沒有匹配,則返回-1
"_x_x".search(/x/)
注:該方法會忽略g
修飾符
var r= /x/g
r.lastIndex =2;
console.log('_x_x'.search(r)) //1
-
replace
方法可以替換匹配的值。
str.replace(正則對象,替換內容)
例如
console.log("aaa".replace(/a/,'b')); //baa
console.log("aaa".replace(/a/g,'b')); //bbb
若標識符設置了g,則全部替換,否則只替換匹配到的第一個
replace
方法第二個參數可以使用美元符號$
,用來只帶替換的內容
-
$&
:指代匹配的子字符串 -
$\
`:指代匹配的字符串前面的文本 -
$ '
:指代匹配的字符串后面的文本 -
$n
:指代匹配成功的第n
組內容,n
是從1開始的 -
$$
:指代美元符號
"abc".replace("b","[$`-$&-$']") // a[a-b-c]c
"hello world".replace(/(\w+)\s(\w+)/,"$2 $1") //world hello
replace
第二個參數還可以是一個函數,函數接收的第一個參數是捕獲到的內容,第二個,第三個....是分組的內容,倒數第二個是捕獲內容在原字符串中的位置,最后一個參數是原字符串
var str = "3 and 5".replace(/[s0-9]+\s+?(and)/,function (match,item1,index,str){
// return match+'hello' // 替換后的str = "3 andhello 5"
// return item1 // 替換后的str = "and 5"
// return index // 替換后的str = "0 5"
return str // 替換后的str = "3 and 5 5"
})
console.log(str);
-
split
方法可以基于指定的分隔符將一個字符串分割成多個子字符串,并將結果放在一個數組中。分隔符可以是字符串,也可以是一個RegExp對象(這個方法不會將字符串看成是正則表達式)。split()
方法可以接受可選的第二個參數,用于指定數組的大小。
var colorText = "red,blue,green,yellow"
var color1 = colorText.split(',');
console.log(color1); //["red", "blue", "green", "yellow"]
var color2 = colorText.split(',',2);
console.log(color2); //["red", "blue"]
var color3 = colorText.split(/[^,]+/);
console.log(color3); //["", ",", ",", ",", ""]
注:如果正則表達式帶有括號,則括號匹配的部分也會作為數組成員返回
console.log("aaa*a*".split(/(a*)/)); //["", "aaa", "*", "a", "*"]
四、基本概念
1、字面量字符和元字符
如果在正則表達式之中,某個字符只表示它字面的含義(就像前面的a和b),那么它們就叫做“字面量字符”
例如:
比如/a/匹配a,/b/匹配b
2、除了字面量字符以外,還有一部分字符有特殊含義,不代表字面的意思。它們叫做“元字符”(metacharacters),主要有以下幾個
- 點字符(.)
點字符(.
)匹配除回車(\r
)、換行(\n
)、行分隔符(\u2028
)和段分隔符(\u2029
)以外的所有字符。
注:回車(\r
)不一定換行(\n
)
- 位置字符
^ 表示字符串的開始位置
$ 表示字符串的結束位置
// test必須出現在開始位置
/^test/.test('test123') // true
// test必須出現在結束位置
/test$/.test('new test') // true
// 從開始位置到結束位置只有test
/^test$/.test('test') // true
/^test$/.test('test test') // false
- 選擇符(
|
)
選擇符會包括它前后的多個字符,比如/ab|cd/
指的是匹配ab
或者cd
,而不是指匹配b
或者c
/ab|cd/.test("abef") //true
/ab|cd/.test("cdef") //true
如果向改變這個行為可以使用圓括號。
/a( |\t)b/.test("a\tb") //true
指匹配a和b之間有一個空格或者是制表符
- 轉義符
正則表達式中那些有特殊含義的字符,如果要匹配它們本身,就需要在它們前面要加上反斜杠。比如要匹配加號,就要寫成\+
/1+1/.test('1+1') // false
/1\+1/.test('1+1') // true
注:需要轉義的字符:
^、.、[、$、(、)、|、*、+、?、{ 和 \\
- 字符類
字符類表示有一系列字符可供選擇,只要匹配其中一個就可以了。所有可供選擇的字符都放在方括號內,比如[xyz]
表示x、y、z
之中任選一個匹配
注:如果方括號內的第一個字符是[^]
,則表示除了字符類之中的字符,其他字符都可以匹配。
例如:
[^xyz]表示除了`x、y、z`之外都可以匹配
/[^abc]/.test('hello world') // true
/[^abc]/.test('bbc') // false
如果方括號內沒有其他字符,即只有[^]
,就表示匹配一切字符,其中包括換行符和回車符,而點號(.)
是不包括換行符和回車符的。
var s = "Please yes\nmake my day!"
console.log(s.match(/yes.*day/)); //null
console.log(s.match(/yes[^]*day/)); //["yes?make my day", index: 7, input: "Please yes?make my day!"]
console.log(s); //Please yes
make my day!
- 連字符(
-
) 表示范圍
例如:
/a-z/.test('b') // false
/[a-z]/.test('b') // true
注:另外,不要過分使用連字符,設定一個很大的范圍,否則很可能選中意料之外的字符。最典型的例子就是[A-z]
,表面上它是選中從大寫的A到小寫的z之間52個字母,但是由于在ASCII編碼之中,大寫字母與小寫字母之間還有其他字符,結果就會出現意料之外的結果。
/[A-z]/.test('\\') // true
上面代碼中,由于反斜杠(\ \)
的ASCII碼在大寫字母與小寫字母之間,結果會被選中。
- 預定義模式
預定義模式指的是某些常見模式的簡寫方式。
\d 匹配0-9之間的任一數字,相當于[0-9]。
\D 匹配所有0-9以外的字符,相當于[^0-9]。
\w 匹配任意的字母、數字和下劃線,相當于[A-Za-z0-9_]。
\W 除所有字母、數字和下劃線以外的字符,相當于[^A-Za-z0-9_]。
\s 匹配空格(包括制表符、空格符、斷行符等),相等于[\t\r\n\v\f]。
\S 匹配非空格的字符,相當于[^\t\r\n\v\f]。
\b 匹配詞的邊界。
\B 匹配非詞邊界,即在詞的內部。
例如:
/\s\w*/.exec('hello world') // [" world"]
/\bworld/.test('hello world') // true
/\bworld/.test('hello-world') // true
/\bworld/.test('helloworld') // false
//單邊邊界:指單詞的前面或者后面不是\w
// \B的例子
/\Bworld/.test('hello-world') // false
/\Bworld/.test('helloworld') // true
注:通常,正則表達式遇到換行符(\n)就會停止匹配。
var html = "<b>Hello</b>\n<i>world!</i>";
/.*/.exec(html)[0]
// "<b>Hello</b>"
- 重復類
{n}:重復n次
{n,}:至少重復n次
{n,m}:至少重復n次,之多重復m次
- 量詞符
?:某個模式出現0次或1次,等同于{0,1}
*:表示某個模式出現0次或多次,等同于{0,}
+:表示某個模式出現1次或多次,等同于{1,}
五、高級應用
1、貪婪模式:
三個量詞符,默認情況下都是最大可能匹配,即匹配直到下一個字符不滿足匹配規則為止。這被稱為貪婪模式.
例如:
var s = 'aaa';
s.match(/a+/) // ["aaa"]
2、惰性模式:
盡可能少的匹配,一旦匹配即終止
常用惰性模式:
?:表示某個模式出現0次或多次,匹配時采用非貪婪模式。
+?:表示某個模式出現1次或多次,匹配時采用非貪婪模式
例如:
var s = 'aaa';
s.match(/a+?/) // ["a"]
3、組匹配(捕獲模式)
也就是一次性匹配多個字符。
例如:
/fred+/.test('fredd') // true
/(fred)+/.test('fredfred') // true
上面代碼中,第一個模式沒有括號,結果+只表示重復字母d
,第二個模式有括號,結果+
就表示匹配“fred”
這個詞。
注:在正則表達式的內部,可以用\n
引用括號匹配的內容
例如:
/(.)b(.)\1b\2/.test("abcabc") //true
括號還可以嵌套
console.log(/y((..)\2)\1/.test("yabababab")); //true
4、非捕獲組
(?:x)
稱為非捕獲組,表示不返回該組匹配的內容,即匹配的結果中不計入這個括號。
例如:
var m = 'abc'.match(/(?:.)b(.)/);
m // ["abc", "c"]
5、先行斷言
x(?=y)
稱為先行斷言,x只有在y前面才匹配,y不會被計入返回結果
例如:
var m = 'abc'.match(/b(?=c)/);
m // ["b"]
5、先行否定斷言
x(?!y)
稱為先行否定斷言,x只有不在y前面才匹配,y不會被計入返回結果
例如:
/\d+(?!\.)/.exec('3.14')
// ["14"]
任務代碼:
html:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>正則表達式入門</title>
<style type="text/css">
#wrap{
width: 500px;
margin: 100px auto;
}
</style>
<script type="text/javascript" src='index.js'></script>
</head>
<body>
<div id="wrap">
<h1>驗證手機號</h1>
<input type="text" name="" id="inp" placeholder="請輸入電話號碼">
<button type="button" id='btn'>點我驗證是否為手機號碼</button>
<h1>驗證是否有相鄰的重復單詞</h1>
<input type="text" name="" id="inp1" placeholder="請輸入英文字母組成的單詞">
<button type="button" id='btn1'>點我驗證相鄰單詞是否重復</button>
</div>
</body>
</html>
js代碼:
/*
電話號碼前三位規則:
聯通:186 185 170 156 155 130 131 132
移動:139 138 137 136 135 134 178 188 187 183 182 159 158 157 152 150 147
電信:189 180 170 153 133
第一位全是1
第二位:3 4 5 7 8
第三位:0 1 2 3 4 5 6 7 8 9
*/
window.onload = function (){
var oBtn = document.getElementById('btn'),
oBtn1 = document.getElementById('btn1'),
oInp = document.getElementById("inp"),
oInp1= document.getElementById("inp1");
// 驗證手機號
oBtn.addEventListener('click',function (){
var oText =oInp.value,
re = /^1[34578][0-9]{9}$/;
alert(re.test(oText))
},false)
// 判斷相鄰單詞是否重復
oBtn1.addEventListener("click",function (){
var oText1 = oInp1.value.replace(/^\s+|\s+$/g,''),//先去除輸入的整個字符串的前后空格
re = /\b([a-zA-Z]+)\s+\1\b/; //使用\b詞邊界(詞邊界是非\w)
alert(re.test(oText1));
/*
\b 元字符匹配單詞邊界。(這里的單詞指的是\w匹配的數字、字母、下劃線 :[a-zA-Z0-9])
在單詞邊界匹配的位置,單詞字符后面或前面不與另一個單詞字符直接相鄰。請注意,匹配的單詞邊界并不包含在匹配中。換句話說,匹配的單詞邊界的長度為零。
提示:\b 元字符通常用于查找位于單詞的開頭或結尾的匹配。
另外:"\b"只有在字符組中,它表示的是退格鍵,即 [a-z\b]
*/
})
}