2017百度前端技術學院- 正則表達式之入門

任務效果預覽
源碼地址

一、創建一個正則表達式

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():返回一個數組,成員是所有匹配的子字符串,matchexec類似,匹配成功則返回一個數組,否則返回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"]

因此,execmatch更強大
設置正則表達式的·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]
                     */
            })
        }

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 230,182評論 6 543
  • 序言:濱河連續發生了三起死亡事件,死亡現場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發現死者居然都...
    沈念sama閱讀 99,489評論 3 429
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 178,290評論 0 383
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 63,776評論 1 317
  • 正文 為了忘掉前任,我火速辦了婚禮,結果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當我...
    茶點故事閱讀 72,510評論 6 412
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發上,一...
    開封第一講書人閱讀 55,866評論 1 328
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當著我的面吹牛,可吹牛的內容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,860評論 3 447
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 43,036評論 0 290
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當地人在樹林里發現了一具尸體,經...
    沈念sama閱讀 49,585評論 1 336
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 41,331評論 3 358
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發現自己被綠了。 大學時的朋友給我發了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 43,536評論 1 374
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 39,058評論 5 363
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質發生泄漏。R本人自食惡果不足惜,卻給世界環境...
    茶點故事閱讀 44,754評論 3 349
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 35,154評論 0 28
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 36,469評論 1 295
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 52,273評論 3 399
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 48,505評論 2 379

推薦閱讀更多精彩內容