主頁 >  其他 > JS 正則運算式詳解 學習筆記

JS 正則運算式詳解 學習筆記

2020-09-15 16:00:54 其他

JS 正則運算式:(RegularExpression)

正則運算式的含義:

正則運算式是一種字串匹配模式,在javascript中的作用主要是用來匹配特定形式的字符,

定義一個正則運算式:

我們想要定義一個正則運算式有兩種方法:

  1. 正則運算式直接量
  2. 創建正則運算式物件

正則運算式直接量:

var reg = /s$/

我們可以使用正則運算式直接量來創建一個正則運算式,其中格式為/xxx/,用兩個反斜杠來表示正則運算式創建的格式,反斜杠中間寫上我們要匹配的字符文本,

創建正則運算式物件:

var reg2 = new RegExp("s$")

RegExp建構式創建正則運算式其實也是很簡單的,建構式接收一個引數,引數型別為字串型別,傳入的字串就是我們要匹配的字串的模板,new RegExp()回傳一個正則運算式物件,

注意:和js中其他直接量不同,正則運算式的直接量會在代碼執行的時候會把/s$/轉變成一個RegExp物件,在舊版本的es3中,當執行到同一段正則運算式的時候會回傳相同的物件,舉個例子:

function createRegExp(){
	var reg = /S$/
    return reg
}
var myreg1 = createRegExp()
var myreg2 = createRegExp()
console.log(myreg1 === myreg2)//true

我們定義了一個函式,用來創建一個正則運算式物件,在全域,我們執行了兩次createRegExp()建構式,將生成的正則運算式物件分別存放在myreg1myreg2中,當我們將其做相等運算時發現,它們指向的是相同的一個物件,也就是說,在es3中,用正則運算式常見的RegExp物件會共享同一個實體,其實這個結論的前提是正則運算式的模式要一致,但是在es5中則是兩個相對獨立的運算式物件:

console.log(myreg1 === myreg2)//false

myreg1和myreg2是相互獨立的,并不都會相互共享記憶體資訊,如:lastIndex后續有講到,

直接量字符:

當我們想要去匹配非法的字符的時候,比如/的時候,我們需要對字符進行轉移,通常的做法是在非法的字符前面加上\,即斜杠,

在正則運算式中,有一些字符有它自己獨特的含義,這些字符有:^ $ . * + = ! : | \ / ( ) [ ] { }等,當我們使用這些符號的時候,它代表的意義已經不是我們字面上所看到的了,假如我們真的只是想單純的想去匹配這些字符怎么辦呢,我們需要對這些字符進行轉義,假如我們想要匹配一個+

var reg = /+/

上面的寫法肯定是不行的,原因是它代表特殊的匹配含義,想要單純的匹配字符我們應該這樣:

var reg = /\+/

我們需要用右斜杠將其轉義后就可以單純的匹配+字符了,

字符類:

將直接量字符單獨放進方括號[]內可以組成一個字符類,一個字符類可以匹配它所包含的任意字符,我的理解是,字符類相當于一個集合,這個集合里面放著我們定義的字符,例如:

var reg = /[abc]/

注意:不用打逗號來表示分割,即不要[a,b,c]這樣的話,也成為了我們字符類里的成員,

上面的運算式的意思是:現在我有一個集合,集合里面放的有ab,c這三個元素,那么正則運算式就用這個集合里的任意一個元素進行匹配,另外,我們可以用^來否定字符類,^符號在正則運算式的意思類似于我們編程語言中!的意思,即為非,[^abc]表示剔除掉集合中的所有元素,就是匹配集合的補集,除了集合中的元素,其他的元素都可以匹配,

[]表示的是字符類,但是有一點值得注意,一個[]代表一個字符,只不過這個字符可能是集合中的任意一個字符,什么意思呢,比如:

var str = '1234a'
var reg = /[asdfg]/
//現在我們的集合里面有a,s,d,f,g這五個元素,但是在匹配的時候只能和字串中的一個進行匹配,
//先和str中的1匹配,看自己的集合中有沒有這個字符,如果沒有再和2匹配,看自己的集合里有沒有這個字符
//以此類推,中括號里有五個字符,并不代表它一次能和字串中的五個字符匹配,而是一個一個的匹配,

字符類可以使用連字符-,來表示字符的范圍,如:[a-zA-Z0-9]:表示這個集合里面的元素是大小寫字母和數字,每一個[]其實都有一個自己的集合,就算你這樣寫[(ab)(cd)]他也只是表示他的集合中有(/a/b/)/c/d這六個字符,

在js中,有一些特定的字符類:

  • [...]:方括號內的任意字符,也就是說這個集合里的元素是所有的字符,
  • [^...]:不在方括號內的任意字符,也就是說是[...]集合的補集,也就相當于這個集合為空,它匹配不了任何字符,
  • .:除了換行符和其他Unicode行終止符之外的任意字符,
  • \w:任何ASCII組成的單詞,等價于:[a-zA-Z0-9]
  • \W:(大寫),任何不是ASCII組成的單詞,等價于:[^a-zA-Z0-9]
  • \s:任何Unicode空白符,
  • \S:任何非Unicode空白符的字符,注意:\w\S不一樣,
  • \d:任何ASCII數字,等價于[0-9]
  • \D:除了ASCII數字之外的任何字符,等價于:[^0-9]
  • [\b]:退出直接量(特例)

在方括號內可以寫這些特殊轉義字符,比如:[\w\s]他代表的含義是匹配任何ASCII組成的單詞和任何Unicode空白符,也就是說[\w\s]字符類的集合是\w\s的并集,

重復:

我們現在學的正則運算式只能匹配單個字符,意思是單個單個的字符匹配,無論是字符類還是使用特定的字符類,它們的區別只是對應集合的差異,在匹配的行為上,都是一次只能對一個字符進行匹配,假如我們要對多個字符進行匹配怎么辦,有人會想到,我可以直接/abcd/,這樣就可以一次性匹配四個字符了,也就是四個四個的去匹配,這樣固然可以,但是有局限性,就是限定死了匹配的內容,只能匹配abcd這四個字,現在我們的需求是匹配兩個任意的數字,那么我們應該怎么辦呢?我們可以這樣寫:

var reg = /\d\d/
//這樣就可以表示一次性匹配兩個數字了

但是這樣寫有一個缺點,假如我們要同時匹配100個數字,難道我們要寫100個\d嗎,正則運算式對于重復有自己的相關優化,

下面是正則運算式的重復字符語法:

  • {n,m}:匹配前一項至少n次,但不能超過m次,
  • {n,}:匹配前一項n次或者更多次,
  • {n}:匹配前一項n次,
  • ?:匹配前一項0次或者1次,也就是說前一項是可選的,等價于{0,1}
  • +:匹配前一項1次或多次,等價于{1,}
  • *:匹配前一項0次或多次,等價于{0,}

上面的不是匹配的次數,而是一次要同時匹配幾個字符,即以幾個字符為單位去匹配,

我們來解決我們前面提到的需求,此時我們要匹配兩個數字(兩個兩個的匹配,兩個數字為一次匹配單位),則可以這樣寫:

var reg =/\d{2}/

實體:

這里有幾個實體:

var reg1 = /\d{2,4}/ //匹配2~4個數字
var reg2 = /\w{3}\d?/ //精確匹配三個單詞和一個可選數字
var reg3 = /\s+javascript\s+/ //匹配前后都帶有一個或者多個空格的"javascript"字串
var reg4 = /[^(]*/ //匹配0個或者多個的非(的字符

因為*?允許字符的匹配可以為0,所以它們允許什么都不匹配,

重復的特性:

貪婪匹配:

我們在分析前面正則運算式重復語法的時候發現,大多數的語法都允許我們去匹配多個,現在我們想一個問題,我有一個字串,然后有一個reg

var str = "aaaa"
var reg = /a+/

此時問題就來了,因為+是允許我們去匹配一個或者多個字符,那么我們是匹配一個還是兩個亦或者全部呢?答案是會匹配全部,在一般情況下,正則運算式使用的是貪婪匹配,即盡可能多的匹配,

非貪婪匹配:

假如我們不想進行貪婪匹配,我們可以使用非貪婪匹配,當我們使用非貪婪匹配的時候,只需要在待匹配的字符后面跟隨一個?即可,例如:??,+?,*?,{1,3}?,比如正則運算式/\d{2,4}?/他也可以匹配兩個或四個數字,但是它會盡可能少的匹配,這里挺有意思的,我們仔細思考什么叫盡可能少的匹配,也就是說在默寫特定的情況下即使你使用了?也不能以最少的來匹配,這就引除了一條重要的概念:

正則運算式的模式匹配總是會尋找字串中第一個可能匹配的位置,

例如:

var str = "aaaab"
var reg = /a+?b/

我們也許希望它會匹配最后一個a和第一個b,但是真正的結果是它會匹配整個字串,原因是因為正則運算式的模式匹配總是會尋找字串中第一個可能匹配的位置,

選擇,分組和參考:

正則運算式的語法還包括指定選擇項子運算式分組參考前一子運算式的特殊字符

指定選擇項:在正則運算式中,我們可以使用|來分隔供選擇的字符,例如:/ab|cd|ef/,意思時匹配abcdef,用集合理論的話就是現在的集合中有三個元素ab/cd/ef,看誰最先符合匹配的標準,一旦有一個元素符合匹配的機制就會停止匹配,無論它右面的元素是什么都會被忽略,

選擇項的嘗試匹配次序是從左到右的,直到發現了匹配項,如果左邊的選擇項被匹配的話,則會直接忽略右邊的選擇項,例如:

var str = "ab"
var reg = /a|ab/

因為a被首先的匹配到,所以ab會被自動忽略,

分組()和參考\n

在正則運算式中,圓括號有多種作用:

  1. 把單獨的項組合成子運算式
  2. 在完整的模式中定義子模式
  3. 允許在同一正則運算式的后部分參考前面的子運算式

在正則運算式中,每一個()內的文本都是一個子運算式,有的子運算式可以參考有的卻不能參考,后面有講到,注意:在正則運算式中假如想要匹配’(’ 和 ")"需要進行轉義,

把單獨的項組合成子運算式

? 把單獨的項組合成子運算式,以便可以像處理獨立單元那樣來使用|,?,+等,

? 項其實就是我們每一次進行模式匹配時所用到的字符模板,項的字符數可以是一個或者多個,比如說:

var str = 'ababab'
var reg = /ab|cd|bab/

這里的ab,cd,bab其實就是項,每一次去進行匹配的時候它會使用這三個里面的某一個去匹配,

var str = "abababab"
var str = /ababa/
//此時ababa就是一個項,他是一個整體,不會把它拆開來分別匹配,
var str = "abababab"
var reg = /abab{2}/
console.log(str.match(reg))
null
//我們可以看到,當使用{2}的時候,它前面的項是b,它等價于reg = /ababb/
//所以不同場景,項的字符個數不一樣,

假如我們想要匹配上面字串的abababab怎么辦,當然,你可以直接寫var reg = /abababab/但是這樣寫太麻煩了,我們可以這樣寫/(abab){2}/,此時,{2}會把(abab)看作一個整體,而不是單獨的把最后一個b看作一個整體,其實還有更簡單的方法/(ab){4}/它等價于/abababab/,實體:

var reg = /(ab|cd)+|ef/

上面的正則運算式表示,可以匹配ef,也可以匹配abcd的一次或多次,簡單說,()在這里的作用就是為?/+/*/$/^/{}這些特殊語法服務的,就是想讓它們知道,你要把哪些字符看做一個整體(項),然后一起操作,默認的情況下它們操作的項只有一個字符,

在完整的模式中定義子模式:

允許在同一正則運算式的后部分參考前面的子運算式

帶圓括號運算式的另一個用途是允許在同一正則運算式的后面參考前面的子運算式,這是通過在字符\后面添加數字來實作的,形如:\3原本的數并不需要轉義,但是我們卻用了\字符,說明這個3有特殊含義,數字代表的是帶有圓括號的子運算式在正則運算式的位置,例如:\1代表對正則運算式中的第一個子運算式進行參考,\2表示對正則運算式中的第二個子運算式進行參考,注意,因為子運算式可以嵌套另一個子運算式,所以它的位置是根據參與計數的左括號的位置來決定的,

注意:對正則運算式中前一個子運算式的參考,并不是指對子運算式模式的參考,而指的是與那個模式相匹配的文本的參考,**如何去理解這句話呢,我們看一段代碼:

var reg = /(ab\d)ccc\1/
var str = "ab1cccab1"
console.log(str.match(reg))

我們也許很清楚的知道列印結果:

[ 'ab1cccab1', 'ab1', index: 0, input: 'ab1cccab1', groups: undefined ]

但是匹配的原理真的是你想像中的那樣嗎?我們再來看一個實體:

var reg = /(ab\d)ccc\1/
var str = "ab1cccab2"
console.log(str.match(reg))

結果:

null

為什么是這個樣子,其實上面的那句話說的已經很明了了,對正則運算式前面子運算式的參考并不是對子運算式的模式的參考,什么是模式的參考?模式的參考指的是,比如現在有一個模式是/ab\d/表示匹配ab然后后面跟一個任意的數字,假如有一個正則運算式參考它的模式,則這個正則運算式也表示匹配ab然后后面跟一個任意的數字,但是人家說的很清楚了,不是參考模式而是參考與那個模式相匹配的文本,即\1代表的是(ab\d)匹配的文本,即:ab1,所以當我們設定str = "ab1cccab2"時,就無法得到匹配的原因,

這樣,參考可以用于實施一條約束,即一個字串的各個獨立的部分都是相同的字符,比如:111111111111,假如我們要匹配這樣的一個字串的話,我們完全可以這樣寫:

var str = "aaaaaaaaaaaaa"
var reg = /(\w)(\1)+/
console.log(str.match(reg))

其中/(\w)(\1)+/表示,第一個是任意的字符,那么(\1)表示的是(\w)匹配到的字符,也就是a+表示a的數量可以有多個,那么就可以把整個字串都匹配下來了,

還有一種子運算式:(?:…),例如:(?:java),雖然這是一個運算式,但是它卻不能參考,也就是說它并不在數字索引的考慮范圍之內,例如:

var reg = /(java)(?:script)\2/
var str = "javascriptscript"
console.log(str.match(reg)) 

結果:

null

我們發現,并不能通過\2來獲取script所以(?:)并不能參與正則運算式的數字索引,而它僅僅適用于分組

正則運算式的選擇,分組和參考字符:

  • |:選擇,匹配的是該符號左邊的子運算式或者右邊的子運算式
  • (...):組合,將幾個項組合為一個單元,這個單元可通過*/+/?/|等符號加以修飾,而且可以記住這個組合項匹配的的字串文本以供此后的參考使用,
  • (?:...):只組合,把項組合得到一個單元,這個單元可通過*/+/?/|等符號加以修飾,但不記憶與該組相匹配的字符,其實(?:...)(...)的區別就是一個匹配的文本能被參考而另一個卻不能,
  • \n:n是數字型別,如:\1,和第n個分組第一次匹配的字符相匹配,組是圓括號中的子運算式(也有可能是嵌套的),組的索引是從左到右的左括號數,(?:形式的分組不編碼,

指定匹配位置:

錨點:

在前面我們知道了關于匹配字符的正則運算式,但是,在正則運算式中,還有一種可以用來匹配位置的語法,

在正則運算式中這些匹配位置的語法元素通常我們叫它們錨元素,最常用的錨元素是^,它用來匹配字串的開始,錨元素$用來匹配字串的結束,當然還有\b表示匹配一個單詞的邊界,

零寬斷言:

零寬斷言是一種位置的匹配機制,它匹配到的內容不會保存到匹配結果中去,最終匹配結果只是一個位置而已,
作用是給指定位置添加一個限定條件,用來規定此位置之前或者之后的字符必須滿足限定條件才能使正則中的字運算式匹配成功,

在js中只支持零寬先行斷言,而零寬先行斷言又可以分為正向零寬先行斷言,和負向零寬先行斷言

正向零寬先行斷言(?=…):

var str = "ab123"
var reg = /ab(?=\d+)/
console.log(str.match(reg))
//[ 'ab', index: 0, input: 'ab123', groups: undefined ]

在這里,(?=\d+)表示的是正向零寬斷言,意思是匹配的字符后面(是一個位置概念,類似于^和$)必須有一個或者多個數字才能匹配成功,我們發現,最后它回傳的是ab,并沒有把后面的數字給回傳,因為零寬斷言(?=\d+)并不匹配任何字符,只是用來規定當前位置的后面必須是一個或多個數字,也就是位置的限制條件,要把ab匹配成功,那么它的后面一定要有一個或多個的數字,我們發現,其實和我們熟知的錨點不同,錨點的位置匹配是固定的,沒有任何的限制條件,但是零寬斷言就不一樣了,它必須有限制,

負向零寬先行斷言(?!..):

var str = "ab123abc"
var reg = /ab(?!\d+)/
console.log(str.match(reg))
//[ 'ab', index: 5, input: 'ab123abc', groups: undefined ]

在這里,(?!...)表示的是負向先行斷言,意思時匹配的字符后面必須沒有一個或多個數字才能匹配成功,和正向零寬先行斷言一樣,負向的也只回傳ab,因為零寬斷言(?!\d+)并不匹配任何字符,只是用來規定當前位置的后面必須不能是一個或多個數字,也就是位置的限制條件,這里回傳的index值為5,說明它匹配的ab并不是開頭的那個,而是后面的,我們發現其實正向零寬斷言是表示?=\d+,即這個位置必須有(等于)這個限制條件,而負向零寬斷言是表示?!\d+,即這個位置必須不能有(不等于)這個條件,其實也就是字面意思!(非)不等于或者和正向的條件相反,

通過這兩個實體,其實我們對零寬斷言有一些的了解,我認為零寬斷言彌補了正則中在字串中間定位位置的機制,我們所熟知的錨點是在邊界上定位位置,

修飾符:

正則運算式的修飾符用于更高級的模式匹配,修飾符的寫法和我們平時的匹配模板不同,他并不是用在雙斜杠內部的,而是外部,在第二個反斜杠的右側,如:/\d/gg就是我們所說的修飾符,

正則運算式修飾符:

  • i:執行不區分大小寫,
  • g:執行一個全域匹配,簡而言之,即 找到所有的匹配,而不是在找到第一個后就停止
  • m:多行匹配,^匹配一行的開頭和字串的開頭,$匹配行的結束和字串的結束,

修飾符可以多個同時存在,比如:/javascript\d+/ig表示匹配是全域匹配且不區分大小寫,

用于模式匹配的String方法:

對于正則匹配,我們一般有兩個側重點,一個是對字串的側重,另一個是對正則運算式的側重,

其中在字串中,我們有四種方法使用正則運算式的方法:

  1. search(reg):search方法有一個引數,代表接收的正則運算式,該方法回傳的是第一個符合匹配的起始位置,如果匹配失敗則回傳-1search不支持全域檢索也即是說它會忽略修飾符g,實體:

    console.log("1234".search(/\d/g))
    //0
    

    假如傳入的引數不是正則運算式,則search會將其轉換成正則運算式,例如:str.search("123")會轉換成str.search(/123/)

  2. replace(reg,str):該方法的作用是執行檢索和替換,它接收兩個引數,第一個是要進行匹配的正則運算式,第二個引數是參與替換的字串,該方法會對要匹配的字串進行檢索,將匹配成功的字串替換成第二個引數中的字串,回傳一個替換好的新串,假如使用了模式匹配修飾符g,則不會只匹配一個,而是將整個字串都檢索,符合匹配的都被替換,如果傳入的第一個引數是一個字串,則會直接搜索這個字串,然后進行替換,且只替換一次,因為它并沒有收到全域匹配的指令**,如果在替換字串中出現了$符號加數字,那么replace將用與指定的子運算式相匹配的文本來替換這兩個字符,**replace方法的第二個引數可以是函式,

    該函式能夠動態的機選替換字串,

    插入特殊變數名:

    $$插入一個 “$”,
    $&插入匹配的子串,
    $插入當前匹配的子串左邊的內容,
    $插入當前匹配的子串右邊的內容,
    $n假如第一個引數是 RegExp物件,并且 n 是個小于100的非負整數,那么插入第 n 個括號匹配的字串,提示:索引是從1開始

    實體:

    var str = "asdfg12dfsdf34"
    var reg = /(\d)(\d)/g
    console.log(str.replace(reg,"$2"))
    //asdfg2dfsdf4
    //運行程序大致為,先匹配到了"12",然后用第二個子運算式的文本,也就是"2"來替換匹配到的"12"字串,
    //然后繼續向下匹配,匹配到"34",然后用第二個子運算式的文本,也就是"4"來替換匹配到的"34"字串,
    //然后回傳新串
    

    這里我們可以看到我們用$2匹配到的文本替換了reg匹配到的值,其實本質上,我們就是用第二個引數的值來替換匹配到的值,那么我們就可以靈活發揮了,例如:

    var str = "asdfg12dfsdf34"
    var reg = /(\d)(\d)/g
    console.log(str.replace(reg,"$2" + "AAAA"))
    //asdfg2AAAAdfsdf4AAAA
    //運行程序是這樣的,我們先匹配到了"12",然后$2代表的是第二個子運算式匹配的文本,即"2",然后進行一個
    //字串加法運算,然后把運算的結果當作參與替換的字串,其實本質上,$2就是一個動態的實時再在的值,
    //之所以是動態的,原因在于每次匹配,第二個子運算式的 值會有所變化,
    

    replac方法中的第二個引數可以為一個函式,我們可以通過函式來對匹配的字符進行操作:

    var str = "asdfg12dfsdf34"
    var reg = /\d\d/g
    console.log(str.replace(reg,function(val){
        console.log(val)
        return "AA" + val
    }))
    

    結果:

    12
    34
    asdfgAA12dfsdfAA34
    
  3. match(reg):該方法是最常用的方法之一,該方法只有一個引數,該引數是我們要匹配的正則運算式,該方法的回傳值是一個陣列,若我們使用了修飾符g,則該方法會進行全域匹配,而回傳的陣列中就是全域匹配成功的字符,假如我們并不進行全域匹配,那么仍然回傳一個陣列,該陣列的一個元素是我們匹配到的字符,而剩下的元素是子運算式匹配的文本,如:

    var str = "123"
    var reg2 = /\d/
    var reg1 = /\d/g
    var reg = /(\d)(\d)(\d)/
    console.log(str.match(reg))
    console.log(str.match(reg1))
    console.log(str.match(reg2))
    

    結果:

    [ '123', '1', '2', '3', index: 0, input: '123', groups: undefined ]
    [ '1', '2', '3' ]
    [ '1', index: 0, input: '123', groups: undefined ]
    
  4. split(string/reg):該方法用以將呼叫它的字串拆分為一個子串組成的陣列,使用的分割符就是傳入的引數,例如

    console.log("1,2,3,4,5".split(","))
    //[ '1', '2', '3', '4', '5' ]
    console.log("1-2-3-4-5".split("-"))
    //['1','2','3','4','5']
    console.log("1 - 2".split(/\s-\s/))
    //['1','2']
    console.log("1 - 2 -        3".split(/\s*-\s*/))
    //[ '1', '2', '3' ]
    

    當我們傳入正則運算式時,split會在字串中匹配相應的字符,將匹配成功的字符作為分隔符來進行分割字串,

RegExp物件:

我們在前面說過,當js引擎在對正則運算式的處理是:假如我們用直接量的方式去創建一個正則運算式,那么js引擎會把它轉化成正則物件,想要獲取正則運算式物件,可以通過RegExp建構式:

var reg = new RegExp("abc")

這樣我們就獲得了一個匹配字串abc的一個正則運算式物件,RegExp可以接收兩個字串引數,第一個引數是我們要匹配的字串模板,也就是直接量正則運算式兩個斜杠之間的文本,在這里需要注意,假如我們使用像\d\s\w\W等這種帶有\字符的這種字符類,必須要把\進行轉義,比如:

var reg = new RegExp("\\d")

在這里我們使用了\\d中的\進行了轉義,RegExp建構式的第二個引數是一個可選引數,它指定的是正則運算式的修飾符,不過只能傳入i/g/m或者它們的組合,例如:

var reg = new RegExp("\\d","g")

既然是物件,那么就會有屬性和方法,接下來我們來看一看正則運算式物件的屬性和方法,

屬性:

  1. source:只讀,字串型別,包含正則運算式的文本,
  2. global:只讀,布爾型別,用以說明運算式是否含有修飾符g
  3. ignoreCase:只讀,布爾型別,用以說明運算式是否含有修飾符i
  4. multiline:只讀,布爾型別,用以說明運算式是否含有修飾符m
  5. lastIndex:可讀寫,number型別,如果匹配模式中使用了修飾符g,這個屬性存盤的是在整個字串下一次檢索開始的位置,這個屬性在后面的物件方法中會用到,

方法:

  1. exec():該函式的第一個引數是待檢索的字串,可以傳入第二引數,第二個引數是修飾符,實體:

    var str = "abcde"
    var reg = new RegExp("\\w\\w")
    console.log(reg.exec(str))
    //[ 'ab', index: 0, input: 'abcde', groups: undefined ]
    

    我們從代碼中可以看到,exec方法對一個指定的字串執行一個正則運算式,簡言之,就是在一個字符中執行檢索匹配,如果沒有找到任何匹配那就回傳null,但是如果找到了一個匹配,它將回傳一個陣列,然后不會再向后進行匹配,這個陣列的第一個元素包含的是與正則運算式相匹配的字串,余下的元素是與圓括號內的子運算式相匹配的子串,例如:

    var str = "abcde"
    var reg = new RegExp("(\\w\\w)(\\w\\w)")
    console.log(reg.exec(str))
    //[ 'abcd', 'ab', 'cd', index: 0, input: 'abcde', groups: undefined ]
    

    match方法不同,就算是你使用了修飾符g,單次執行該函式是不會去進行全域的匹配,實體:

    var str = "123"
    var reg = new RegExp("\\d","g")
    console.log(reg.exec(str))
    //[ '1', index: 0, input: '123', groups: undefined ]
    

    match方法單次執行會進行全域匹配:

    var str = "123"
    var reg = new RegExp("\\d","g")
    console.log(str.match(reg))
    //[ '1', '2', '3' ]
    

    雖然exec的功能簡單,但是多次執行時有一點特別需要注意,那就是它是否帶有修飾符g,我們來看一個例子:

    var str = "abcdefghijklmnopqrst"
    var reg = new RegExp("\\w\\w")
    console.log(reg.exec(str))
    console.log(reg.exec(str))
    console.log(reg.exec(str))
    console.log(reg.exec(str))
    console.log(reg.exec(str))
    console.log(reg.exec(str))
    /*
    [ 'ab', index: 0, input: 'abcdefghijklmnopqrst', groups: undefined ]
    [ 'ab', index: 0, input: 'abcdefghijklmnopqrst', groups: undefined ]
    [ 'ab', index: 0, input: 'abcdefghijklmnopqrst', groups: undefined ]
    [ 'ab', index: 0, input: 'abcdefghijklmnopqrst', groups: undefined ]
    [ 'ab', index: 0, input: 'abcdefghijklmnopqrst', groups: undefined ]
    [ 'ab', index: 0, input: 'abcdefghijklmnopqrst', groups: undefined ]
    */
    

    然后我們再來看一個例子:

    var str = "abcdefghijklmnopqrst"
    var reg = new RegExp("\\w\\w","g")
    console.log(reg.exec(str))
    console.log(reg.exec(str))
    console.log(reg.exec(str))
    console.log(reg.exec(str))
    console.log(reg.exec(str))
    console.log(reg.exec(str))
    /*
    [ 'ab', index: 0, input: 'abcdefghijklmnopqrst', groups: undefined ]
    [ 'cd', index: 2, input: 'abcdefghijklmnopqrst', groups: undefined ]
    [ 'ef', index: 4, input: 'abcdefghijklmnopqrst', groups: undefined ]
    [ 'gh', index: 6, input: 'abcdefghijklmnopqrst', groups: undefined ]
    [ 'ij', index: 8, input: 'abcdefghijklmnopqrst', groups: undefined ]
    [ 'kl', index: 10, input: 'abcdefghijklmnopqrst', groups: undefined ]
    */
    

    我們觀察上面的代碼,我們可以發現,第一個實體是我們不加修飾符g,第二個實體我們加上了修飾符g,我們連續對同一個字串呼叫exec我們可以從列印的結果上看,它們有天壤之別,在第一個實體當中,匹配的元素永遠是ab,且index屬性的值永遠是0,而第二個實體中,匹配的是不同的字符,并且index屬性的值一直是變化的,這就是修飾符gexec函式的宏觀影響,當呼叫exec函式的正則運算式物件具有修飾符g時,它將把當前正則運算式物件的lastIndex屬性設定為緊挨著匹配子串的字符位置,當同一正則運算式第二次呼叫exec函式時,他將從lastIndex所指示的字符處開始檢索,如果exec沒有檢測到任何匹配結果,他會將lastIndex重置為0,這里有一個很有意思的實體:

    var str = "abcdefghijklmnopqrst"
    var str_2 = "zzxxccvvbb"
    var reg = new RegExp("\\w\\w","g")
    console.log(reg.exec(str))
    console.log(reg.exec(str))
    console.log(reg.exec(str_2))
    /*
    [ 'ab', index: 0, input: 'abcdefghijklmnopqrst', groups: undefined ]
    [ 'cd', index: 2, input: 'abcdefghijklmnopqrst', groups: undefined ]
    [ 'cc', index: 4, input: 'zzxxccvvbb', groups: undefined ]
    */
    

    我們可以從實體中對上面的描述會有一個更清楚的理解,當我們第一次執行reg.exec(str)后,此時的reg.lastIndex的值為2,當我們第二次執行reg.exec(str)時,因為需要從reg物件中的lastindex屬性中獲取我檢索的位子,此時的reg.lastIndex的值為2,所以就從2位置開始檢索,檢索完畢后將reg.lastIndex的值設定為4并保存,當去匹配其他字串的時候,需要從lastIndex獲取開始匹配的位置,所以其他的字串會從4這個位置開始匹配,

  2. test(str):該函式接收一個引數,就是我們所要匹配的字串,該函式的作用是檢測目標字串中是否有我們要匹配的字符,如果有就回傳true,如果沒有就回傳false,實體:

    var str = "1asdf"
    var reg = new RegExp("\\d")
    console.log(reg.test(str))
    //true
    

    當我們不添加修飾符g的時候,和exec方法一樣,reg.lastIndex的值永遠為0,每一次的匹配都要從最開始來匹配,但是當我們加上修飾符g的時候,事情就變得好玩了,我們來看一個實體:

    var str = "asd1f"
    var reg = new RegExp("\\d","g")
    console.log(reg.lastIndex)
    console.log(reg.test(str))
    console.log(reg.lastIndex)
    console.log(reg.test(str))
    console.log(reg.lastIndex)
    /*
    0
    true
    4
    false
    0
    */
    

    我們發現,當我們使用修飾符g的時候,和exec一樣,當匹配成功時,lastIndex會被設定為緊挨著匹配子串的字符位置,當有其他的字符呼叫該正則運算式的test函式時,開始檢索的位置就是reg.lastIndex保存的位置,當匹配失敗,則會重置lastIndex的值為0

    exectest不同的是,字串上的方法并不會用到lastIndex這個屬性,本質上,String方法只是簡單地將lastIndex的值重置為0,所以我們每次呼叫相關方法的時候都會從頭開始檢索,

感想:

上述的文章是我在學習js正則運算式自己歸納和理解的,僅供大家參考,若有錯誤,望指正,我將感激不盡,謝謝!

轉載請註明出處,本文鏈接:https://www.uj5u.com/qita/48063.html

標籤:其他

上一篇:JfreeChart常用表格繪制

下一篇:制作游戲時,如何管理游戲資源? 逐行注釋!

標籤雲
其他(157675) Python(38076) JavaScript(25376) Java(17977) C(15215) 區塊鏈(8255) C#(7972) AI(7469) 爪哇(7425) MySQL(7132) html(6777) 基礎類(6313) sql(6102) 熊猫(6058) PHP(5869) 数组(5741) R(5409) Linux(5327) 反应(5209) 腳本語言(PerlPython)(5129) 非技術區(4971) Android(4554) 数据框(4311) css(4259) 节点.js(4032) C語言(3288) json(3245) 列表(3129) 扑(3119) C++語言(3117) 安卓(2998) 打字稿(2995) VBA(2789) Java相關(2746) 疑難問題(2699) 细绳(2522) 單片機工控(2479) iOS(2429) ASP.NET(2402) MongoDB(2323) 麻木的(2285) 正则表达式(2254) 字典(2211) 循环(2198) 迅速(2185) 擅长(2169) 镖(2155) 功能(1967) .NET技术(1958) Web開發(1951) python-3.x(1918) HtmlCss(1915) 弹簧靴(1913) C++(1909) xml(1889) PostgreSQL(1872) .NETCore(1853) 谷歌表格(1846) Unity3D(1843) for循环(1842)

熱門瀏覽
  • 網閘典型架構簡述

    網閘架構一般分為兩種:三主機的三系統架構網閘和雙主機的2+1架構網閘。 三主機架構分別為內端機、外端機和仲裁機。三機無論從軟體和硬體上均各自獨立。首先從硬體上來看,三機都用各自獨立的主板、記憶體及存盤設備。從軟體上來看,三機有各自獨立的作業系統。這樣能達到完全的三機獨立。對于“2+1”系統,“2”分為 ......

    uj5u.com 2020-09-10 02:00:44 more
  • 如何從xshell上傳檔案到centos linux虛擬機里

    如何從xshell上傳檔案到centos linux虛擬機里及:虛擬機CentOs下執行 yum -y install lrzsz命令,出現錯誤:鏡像無法找到軟體包 前言 一、安裝lrzsz步驟 二、上傳檔案 三、遇到的問題及解決方案 總結 前言 提示:其實很簡單,往虛擬機上安裝一個上傳檔案的工具 ......

    uj5u.com 2020-09-10 02:00:47 more
  • 一、SQLMAP入門

    一、SQLMAP入門 1、判斷是否存在注入 sqlmap.py -u 網址/id=1 id=1不可缺少。當注入點后面的引數大于兩個時。需要加雙引號, sqlmap.py -u "網址/id=1&uid=1" 2、判斷文本中的請求是否存在注入 從文本中加載http請求,SQLMAP可以從一個文本檔案中 ......

    uj5u.com 2020-09-10 02:00:50 more
  • Metasploit 簡單使用教程

    metasploit 簡單使用教程 浩先生, 2020-08-28 16:18:25 分類專欄: kail 網路安全 linux 文章標簽: linux資訊安全 編輯 著作權 metasploit 使用教程 前言 一、Metasploit是什么? 二、準備作業 三、具體步驟 前言 Msfconsole ......

    uj5u.com 2020-09-10 02:00:53 more
  • 游戲逆向之驅動層與用戶層通訊

    驅動層代碼: #pragma once #include <ntifs.h> #define add_code CTL_CODE(FILE_DEVICE_UNKNOWN,0x800,METHOD_BUFFERED,FILE_ANY_ACCESS) /* 更多游戲逆向視頻www.yxfzedu.com ......

    uj5u.com 2020-09-10 02:00:56 more
  • 北斗電力時鐘(北斗授時服務器)讓網路資料更精準

    北斗電力時鐘(北斗授時服務器)讓網路資料更精準 北斗電力時鐘(北斗授時服務器)讓網路資料更精準 京準電子科技官微——ahjzsz 近幾年,資訊技術的得了快速發展,互聯網在逐漸普及,其在人們生活和生產中都得到了廣泛應用,并且取得了不錯的應用效果。計算機網路資訊在電力系統中的應用,一方面使電力系統的運行 ......

    uj5u.com 2020-09-10 02:01:03 more
  • 【CTF】CTFHub 技能樹 彩蛋 writeup

    ?碎碎念 CTFHub:https://www.ctfhub.com/ 筆者入門CTF時時剛開始刷的是bugku的舊平臺,后來才有了CTFHub。 感覺不論是網頁UI設計,還是題目質量,賽事跟蹤,工具軟體都做得很不錯。 而且因為獨到的金幣制度的確讓人有一種想去刷題賺金幣的感覺。 個人還是非常喜歡這個 ......

    uj5u.com 2020-09-10 02:04:05 more
  • 02windows基礎操作

    我學到了一下幾點 Windows系統目錄結構與滲透的作用 常見Windows的服務詳解 Windows埠詳解 常用的Windows注冊表詳解 hacker DOS命令詳解(net user / type /md /rd/ dir /cd /net use copy、批處理 等) 利用dos命令制作 ......

    uj5u.com 2020-09-10 02:04:18 more
  • 03.Linux基礎操作

    我學到了以下幾點 01Linux系統介紹02系統安裝,密碼啊破解03Linux常用命令04LAMP 01LINUX windows: win03 8 12 16 19 配置不繁瑣 Linux:redhat,centos(紅帽社區版),Ubuntu server,suse unix:金融機構,證券,銀 ......

    uj5u.com 2020-09-10 02:04:30 more
  • 05HTML

    01HTML介紹 02頭部標簽講解03基礎標簽講解04表單標簽講解 HTML前段語言 js1.了解代碼2.根據代碼 懂得挖掘漏洞 (POST注入/XSS漏洞上傳)3.黑帽seo 白帽seo 客戶網站被黑帽植入劫持代碼如何處理4.熟悉html表單 <html><head><title>TDK標題,描述 ......

    uj5u.com 2020-09-10 02:04:36 more
最新发布
  • 2023年最新微信小程式抓包教程

    01 開門見山 隔一個月發一篇文章,不過分。 首先回顧一下《微信系結手機號資料庫被脫庫事件》,我也是第一時間得知了這個訊息,然后跟蹤了整件事情的經過。下面是這起事件的相關截圖以及近日流出的一萬條資料樣本: 個人認為這件事也沒什么,還不如關注一下之前45億快遞資料查詢渠道疑似在近日復活的訊息。 訊息是 ......

    uj5u.com 2023-04-20 08:48:24 more
  • web3 產品介紹:metamask 錢包 使用最多的瀏覽器插件錢包

    Metamask錢包是一種基于區塊鏈技術的數字貨幣錢包,它允許用戶在安全、便捷的環境下管理自己的加密資產。Metamask錢包是以太坊生態系統中最流行的錢包之一,它具有易于使用、安全性高和功能強大等優點。 本文將詳細介紹Metamask錢包的功能和使用方法。 一、 Metamask錢包的功能 數字資 ......

    uj5u.com 2023-04-20 08:47:46 more
  • vulnhub_Earth

    前言 靶機地址->>>vulnhub_Earth 攻擊機ip:192.168.20.121 靶機ip:192.168.20.122 參考文章 https://www.cnblogs.com/Jing-X/archive/2022/04/03/16097695.html https://www.cnb ......

    uj5u.com 2023-04-20 07:46:20 more
  • 從4k到42k,軟體測驗工程師的漲薪史,給我看哭了

    清明節一過,盲猜大家已經無心上班,在數著日子準備過五一,但一想到銀行卡里的余額……瞬間心情就不美麗了。最近,2023年高校畢業生就業調查顯示,本科畢業月平均起薪為5825元。調查一出,便有很多同學表示自己又被平均了。看著這一資料,不免讓人想到前不久中國青年報的一項調查:近六成大學生認為畢業10年內會 ......

    uj5u.com 2023-04-20 07:44:00 more
  • 最新版本 Stable Diffusion 開源 AI 繪畫工具之中文自動提詞篇

    🎈 標簽生成器 由于輸入正向提示詞 prompt 和反向提示詞 negative prompt 都是使用英文,所以對學習母語的我們非常不友好 使用網址:https://tinygeeker.github.io/p/ai-prompt-generator 這個網址是為了讓大家在使用 AI 繪畫的時候 ......

    uj5u.com 2023-04-20 07:43:36 more
  • 漫談前端自動化測驗演進之路及測驗工具分析

    隨著前端技術的不斷發展和應用程式的日益復雜,前端自動化測驗也在不斷演進。隨著 Web 應用程式變得越來越復雜,自動化測驗的需求也越來越高。如今,自動化測驗已經成為 Web 應用程式開發程序中不可或缺的一部分,它們可以幫助開發人員更快地發現和修復錯誤,提高應用程式的性能和可靠性。 ......

    uj5u.com 2023-04-20 07:43:16 more
  • CANN開發實踐:4個DVPP記憶體問題的典型案例解讀

    摘要:由于DVPP媒體資料處理功能對存放輸入、輸出資料的記憶體有更高的要求(例如,記憶體首地址128位元組對齊),因此需呼叫專用的記憶體申請介面,那么本期就分享幾個關于DVPP記憶體問題的典型案例,并給出原因分析及解決方法。 本文分享自華為云社區《FAQ_DVPP記憶體問題案例》,作者:昇騰CANN。 DVPP ......

    uj5u.com 2023-04-20 07:43:03 more
  • msf學習

    msf學習 以kali自帶的msf為例 一、msf核心模塊與功能 msf模塊都放在/usr/share/metasploit-framework/modules目錄下 1、auxiliary 輔助模塊,輔助滲透(埠掃描、登錄密碼爆破、漏洞驗證等) 2、encoders 編碼器模塊,主要包含各種編碼 ......

    uj5u.com 2023-04-20 07:42:59 more
  • Halcon軟體安裝與界面簡介

    1. 下載Halcon17版本到到本地 2. 雙擊安裝包后 3. 步驟如下 1.2 Halcon軟體安裝 界面分為四大塊 1. Halcon的五個助手 1) 影像采集助手:與相機連接,設定相機引數,采集影像 2) 標定助手:九點標定或是其它的標定,生成標定檔案及內參外參,可以將像素單位轉換為長度單位 ......

    uj5u.com 2023-04-20 07:42:17 more
  • 在MacOS下使用Unity3D開發游戲

    第一次發博客,先發一下我的游戲開發環境吧。 去年2月份買了一臺MacBookPro2021 M1pro(以下簡稱mbp),這一年來一直在用mbp開發游戲。我大致分享一下我的開發工具以及使用體驗。 1、Unity 官網鏈接: https://unity.cn/releases 我一般使用的Apple ......

    uj5u.com 2023-04-20 07:40:19 more