為什么要學正則表達式
雖然很多web開發者在忽視正則表達式后,還可以順利工作,但在javascript中還存在一些問題,如果不用正則表達式,是沒辦法進行很好的解決的.
當然,也許還有其他的方式能夠解決相同的問題.但通常,用一句正確的正則表達式很有可能就可以省略半屏幕的代碼.
為什么正則表達式很牛假設我們要驗證一個字符串是否為格式正確的手機號碼.手機號碼開頭都是1,然后后面都是數字,然后長度都為11位
讓我們創建一個函數,對一個輸入內容進行驗證
function isPhoneNumber(candidate){ if(typeof candidate !== "string" || candidate.length!=11){ return false; //過濾明顯不符合條件的輸入內容 } if(isNaN(candidate)){ return false; //過濾非純數字的輸入內容 } return true; }
雖然這段代碼實現的很合理,檢查了輸入內容的類型和長度,但是對于一個簡單的手機號碼檢查,看起來依然有太多的代碼
現在考慮這樣一種方式
function isPhoneNumber(candidate){ return /^1[0-9]{10}$/.test(candidate) }
除了函數體內的一些深奧的語法以外,這種方式看起來更簡潔,更優雅,不是嗎?
這就是正則表達式的威力,而且這只是它冰山的一角.如果語法看起來像鍵盤上爬行的蜥蜴的話,也不要擔心.
讓我們開始對正則表達式進行深挖,要學習正則表達式,就先了解正則表達式出現的由來
正則表達式解釋"正則表達式(regular expression)" 這個詞源于中世紀的數學,當時,一個名叫Stephen Kleene的數學家,使用了一個名為"正則集合"的數學符號描述自動計算模式.但這不會幫助我們了解任何關于正則表達式的內容,那么讓我們把它簡單化,正則表達式通常被稱為一個模式(pattern),是一個用簡單方式描述或者匹配一系列符合某個語法規則的字符串.表達式本身包含了允許定義這些模式的術語和操作符.我們很快就會看到這些術語和操作符.
在 javascript 中,與大多數其他對象類型一樣,有兩種方式可以創建正則表達式:通過正則表達式字面量,或者通過構造 RegExp 對象的實例.
例如,如果要創建一個正則表達式 (或簡稱為正則(regex)),用于精確匹配字符串 "test" ,可以使用正則字面量:
var pattern = /test/;
正斜杠可能看起來有點奇怪,但是就像字符串使用引號進行界定的一樣,正則字面量是用正斜杠進行界定的.
或者,我們可以構造一個 RegExp 實例,將正則作為字符串傳入:
var pattern = new RexExp("test");
這兩種格式在pattern變量中創建的正則表達式都是一樣的.
在開發過程中,如果正則是已知的,則優先選擇字面量語法,而構造器方式則是用于在運行時,通過動態創建字符串來構建正則表達式.
字面量語法優先于用字符串構建正則表達式的其中一個原因是反斜杠字符在正則表達式中發揮重要的作用(很快就能看到).但由于反斜杠字符在普通字符串中也是一個轉義字符,所以,如果要在字符串內表示反斜杠,我們就要使用 (兩個反斜杠).這回讓本來語法就很神秘的正則表達式變得更加怪異了.
除了表達本身,還有三個標志可以與正則表達式進行關聯.
i 讓正則表達式不區分大小寫,所以/test/i不僅可以匹配 "test" ,還可以匹配 "Test" "TEST" "tEsT" 等.
g 匹配模式中的所有實例,而不是默認的只匹配第一次出現的結果
m 允許匹配多個行,比如可以匹配文本區元素(textarea)中的字
這些標志將附加到字面量尾部(例如: /test/ig) 或者作為 RegExp 構造器的第二個字符參數 (new RegExp("test","ig")) .
RegExp 對象方法方法 | 描述 |
---|---|
compile | 編譯正則表達式。 |
exec | 檢索字符串中指定的值。返回找到的值,并確定其位置。 |
test | 檢索字符串中指定的值。返回 true 或 false。 |
例子:
需要注意的是String對象也有個match方法,也可以檢索目標字符串,用法和RegExp的exec方法類似,區別是
exec是正則表達式的方法,而不是字符串的方法,它的參數才是字符串
exec和match返回的都是數組,但是match是返回所有匹配的字符串合成的數組,但是正則表達式必須指定全局g屬性才能返回所有匹配,不指定g屬性則會返回一個只有一個元素的數組。exec永遠返回與第一個匹配相關的信息,其返回數組包括第一個匹配的字串,所有分組的反向引用。
參考資料:http://www.jb51.net/article/46374.htm
?
術語與操作符正則表達式,就像我們熟悉的大多數其他表達式一樣,由術語和驗證這些術語的操作符組成.在接下來的小節中,我們將了解這些術語和操作符,看看它們是如何用于表達模式的.
精確匹配如果一個字符不是特殊字符或操作符(后續會進行介紹),則表示該字符必須在表達式中出現.例如,在/test/正則中,有4個術語,它們表示這些字符必須在一個字符串中出現,才能匹配該模式.
一個接一個的字符,隱式表達了"后面跟著(followed by)"這樣一個操作.所以,/test/的意思是說, "t" 后面跟著 "e","e" 后面跟著 "s","s" 后面又跟著 "t".
匹配一類字符很多時候,我們并不像匹配一個特定的字符,而是想匹配一個有限字符集中的某一個字符.我們可以通過將字符集放到中括號內,來指定該字符集操作符(也被稱為字符類(character class)操作符): [abc]
上述示例,是說我們要匹配 "a" "b" "c" 中的任何一個字符.
有的時候,我們想要匹配一組有限字符集以外的字符.可以通過在中括號第一個開括號后面加一個插入符(^)來實現,比如:
[^abc]
其意義將改變為:除了 "a" "b" 或 "c" 以外的任意字符.
在字符集操作方面,還有一個更加重要的變異操作: 指定一個范圍. 例如,如果要匹配 "a" 和 "m" 之間的任何一個小寫字母,我們可以這樣寫: [abcdefghijklm]但可以寫成更加簡潔的 [a-m]
中橫線表示從 "a" 到 "m" 之間的所有字符 (包含 a 和 m,按字典順序)都在該字符集內.
轉義并不是所有的字符和其字符字面量都是等價的.當然,所有的字母和十進制數字字符都能代表自己,但是,我們很快就會發現.像$ 和點(.) 這樣的特殊字符,表示的是他們自身以外的東西,或者表示為驗證術語的操作符. 事實上,我們已經看到了如何用[、]、-、^ 字符表示它們自身以外的東西
如果我們需要匹配[、]、$、^或其他這樣的特殊字符,該怎么辦?在正則里,使用反斜杠可以對任意字符進行轉義,讓被轉義字符作為字符本身進行匹配.所以,[表示要匹配[字符.兩個反斜杠()則匹配一個反斜杠
匹配開始于匹配結束我們可能經常需要確保模式匹配一個字符串的開始,或者一個字符串的結束.插入符號(^),如果作為正則表達式的第一個字符,則表示要從字符串的開頭進行匹配,這樣/^test/就只能匹配以 "test" 開頭的字符串了.(注意,這只是&字符的一個重載,它還可以用于否定一個字符類集,比如 /[^abc]/ 用于選擇除了除了 "a" "b" 或 "c" 以外的任意字符)
類似的,美元符號$表示該模式必須出現在字符串的結尾:/test$/.
同時使用^和$則表明指定的模式必須包含整個候選字符串.
重復出現如果要匹配連續的4個 "a" 字符,可以用/aaaa/來表示,但如果我們想匹配任意數量的相同字符串呢?
在重復選項上,正則表達式提供了很多方式.
在一個字符后面加一個問號( ? ),可以定義為該字符是可選的(也就是,可以出現一次,或根本不出現)
如果一個字符要出現一次或多次,可以使用加號(+),例如/t+est/可以匹配"test","ttest","tttest",而不能匹配"est"
如果一個字符要出現零次或多次,可以使用星號( * ),例如/t*est/可以匹配"test","ttest","tttest",以及"est"
也可以在字符后面的花括號里指定一個數字來表示重復次數,例如,/a{4}/表示匹配含有連續四個"a"字符的字符串
也可以在字符后面的花括號里指定兩個數字(用逗號隔開)來表示重復次數區間,例如,/a{4,10}/表示匹配任何含有連續4個至10個 "a" 字符的字符串.
次數區間的第二個值是可選的(但是要保留逗號),其表示一個開區間.例如,/a{4,}/表示匹配任何含有連續4個或多于4個 "a" 字符的字符串.
這些重復操作符可以是貪婪的(greedy)或非貪婪的(nongreedy).默認情況下,它們是貪婪的:它們匹配所有的字符組合.在操作符后面加一個問號?字符(?操作符的一個重載),如 a+?,可以讓該表達式變成非貪婪的:進行最小限度的匹配
舉個例子,如果我們對字符串 "aaa" 進行匹配,正則表達式 /a+/將匹配所有這三個字符,而非貪婪表達式/a+?/ 則只匹配一個 "a" 字符,因為一個a字符就可以符合a+術語.
預定義字符類有一些我們想匹配的字符,是不可能用字面量字符來表示的(如像回車的控制字符),還有一些我們可能經常想匹配的字符類,比如小數位數或一組空白字符.正則表達式語法提供了很多表示這些字符或常用類的預定義術語,這樣在正則表達式中,我們就可以使用這些控制字符進行匹配了,因此,我們不需要再去依靠常用的字符集.
下面列出了這些術語以及它們表示的字符或字符集.
預定義術語 | 匹配內容 |
---|---|
水平制表符 | |
空格 | |
v | 垂直制表符 |
f | 換頁符 |
回車 | |
換行符 | |
cA: cZ | 控制符,例如cM 匹配一個Control-M |
x0000:xFFFF | 十六進制Unicode碼 |
x00:xFF | 十六進制ASCII碼 |
. | 匹配除了新行( )之外的任意字符 |
d | 匹配任意數字,等價于[0-9] |
D | 匹配任意非數字,等價于[^0-9] |
w | 匹配包括下劃線的任意單詞字符,等價于[A-Za-z0-0] |
W | 匹配任何非單詞字符,等價于[^A-Za-z0-9] |
s | 匹配任何空白字符,包括空格,制表符,換頁符 |
S | 匹配任何非空白字符 |
匹配單詞邊界 | |
B | 匹配非單詞邊界 |
這些預定義集,讓正則表達式看起來不那么過于神秘了.
分組到目前為止,我們看到的操作符(如+和*)只能影響前面的術語.如果將操作符應用于一組術語,可以像數學表達式一樣在該組上使用小括號.例如,/(ab)+/匹配一個或多個連續出現的字字符串 "ab".
當正則表達式有一部分使用括號進行分組時,它具有雙重責任,同時也創建所謂的捕獲(capture).正則表達式有很多捕獲,我們將在下面對其進行更深入的討論.
或操作符(OR)可以用豎線(|)字符表示或者的關系.例如:/a|b/匹配 "a" 或 "b" 字符,/(ab)+|(cd)+/ 則匹配出現一次或多次的 "ab" 或 "cd".
反向引用正則表達式中最復雜的術語是在正則中所定義的捕獲(captures)的反向引用,我們將在后面幾節花很大篇幅來介紹捕獲方面的內容,但現在就將捕獲作為正則表達式中能夠成功匹配術語時的候選字符串.
這種術語表示法是在反斜杠后面加一個要引用的捕獲數量,該數字從1開始,如1,2等
舉例來說,/^([dtn])a1/表示可以任意一個以 "d" "t" "n" 開頭,且后面跟著一個 a 字符,并且后面跟著的是和第一個捕獲相同字符的字符串.后面這一點很重要! 它和/^[dtn]a[dtn]/不一樣,因為a后面跟著的雖然也是"d" "t" "n" 中的一個,但可能和開頭字符不同,例如:在全局模式下,有兩個字符串"dad" 和 "dat" /^([dtn])a1/會選中 "dad",而不會選中 "dat",
/^[dtn]a[dtn]/ 既選中 "dad",也會選中 "dat"
要匹配像 " whatever" 這樣的元素,不適用反向引用,是無法做到的,因為我們無法知道關閉標簽和開始標簽是否匹配.
例如:/<(w+).+1>/g就可以選中正常閉合的簡單標簽
正則在線測試
在上面的代碼中,我們使用1引用了表達式中的第一個捕獲,在本例中,該捕獲是標簽名稱
還有一個方法可以獲取捕捉的引用,那就是通過調用String對象的replace()方法替換字符串.在這里,我們使用$1 $2 $3 語法表示每個捕獲的數字.
例子:
var pattern=/([A-Z])/g; var str="fontFamily"; console.log(str.replace(pattern,"-$1").toLowerCase()); //font-family
在上面的代碼中,首先獲取的捕獲值(在本例中是大寫字母F),在替換字符串中進行了引用(通過$1).這種方式允許我們制定一個替換字符串,即便是在運行之前還不知道它的值.這是個強大的武器.
這種可以引用正則表達式捕捉結果的能力,讓很多本來很復雜困難的代碼變得相當簡單.其富有表現力的特性,將本來可能很遲鈍,復雜且冗長的代碼,最終變成了一些簡短的語句.
分組與捕獲有時候我們需要在一個字符串里找到特定的數據,比如需要在爬蟲爬到的數據里找到特定的數據,比如天氣溫度,用戶id,特定標簽里面的內容.拿在特定標簽里找里面的內容來舉例,用正則匹配的話我們通常會先找到這個標簽,比如<(strong).+1>,這樣就能匹配到整個strong標簽和strong標簽里面的內容了,
我們找到了strong標簽和它里面的內容,那么又怎么找到strong標簽里面的test呢?
其實,只需要給"".+""加個括號就行
于是我們看到匹配內容多了個test
由于返回的匹配是個數組,所以我們只需要用數組下標就能取到test這個值
為什么加個括號就能取到test了呢 ?
我們前面已經知道了小括號具有雙重責任,不僅可以用來分組,還會創建所謂的 "捕獲" .
因此,使用小括號指定一個子表達式后,匹配這個子表達式的文本(也就是此分組捕獲的內容)可以在表達式或其它程序中作進一步的處理。
既然小括號既有分組的作用,又有捕獲的作用,如果我們只想分組,又不想捕獲怎么辦呢?
思考一下如下的正則表達式:
var pattern=/((good-)+)man/;
在單詞 "man" 前面,允許前綴 "good" 出現一次或多次,并且希望捕獲整個前綴.這個正則表達式需要兩層括號
定義捕獲(man 之前的所有字符串)的小括號
針對+操作符,對 "good-" 文本進行分組的小括號
一切運行正常,但由于括號分組的功能,不僅是單一目標捕獲
要讓一組括號不進行結果捕獲,正則表達式的語法允許我們在開始括號后加一個 ?: 標記.這就是所謂的 被動表達式
將我們的正則表達式修改成如下這樣:
var pattern=/((?:good-)+)man/;
該表達式只會為外層的括號創建捕獲.內層括號被轉換為一個被動子表達式
利用函數進行替換String的replace()方法是一個強大且靈活的方法,將正則表達式作為replace()方法的第一個參數時,導致在該模式的匹配元素(全局匹配的話,就是多個匹配元素)上進行替換,而不是在固定字符串上進行替換.
舉個例子,假如需要讓所有的大寫字符串都替換成"X",我們可以這樣編寫:
"ABCEDfg".replace(/[A-Z]/g,"X")
其結果為 "XXXXXfg". 很不錯.
不過,獲取replace()最強大的特性是可以接受一個函數作為替換值,而不是一個固定的字符串.
當替換值(第二個參數)是一個函數時,每個匹配都會調用該函數(記住,全局搜索會在源字符串中匹配所有的模式實例)并帶有一串參數列表.
匹配的完整文本.
匹配到捕獲,一個捕獲對應一個參數
匹配字符在源字符串中的索引
源字符串
函數的返回值是即將要替換掉值.
這給了我們很多思考的余地,讓我們在運行時確定應該替換的字符串,并掌握大量與匹配特性有關的信息.
例如,在下面的代碼中,我們使用一個函數,動態地將中橫線分割的字符轉換成等價的駝峰拼寫字符.
function upper(all,letter){ return letter.toUpperCase(); } var pattern=/-(w)(w)/g; var str="border-bottom-width"; console.log(str.replace(pattern,upper)); //borderBttomWdth
在這里,我們提供了一個正則表達式,用于匹配中橫線字符后的任意一個字符.全局正則中的捕獲結果就是該匹配的字符(不包括之中橫線).函數在每次被調用的時候(本例中是兩次),傳入匹配的完整的字符串作為第一個參數,捕獲結果(本例只有一個)作為第二個參數.我們對其他參數不感興趣,所以沒有指定他們.
函數在第一次被調用的時候,傳入了 "-b" 和 "b" ,第二次被調用的時候傳入的是 "-w" 和 "w",在本例中,將捕獲字符轉換成大寫,并作為替換值返回.最終,我們將 "-b" 替換成了 "B",將 "-w" 替換成了 "W"
利用正則表達式解決常見問題 修剪字符串將字符串前后多余的空格進行刪除是一種常見的需求,但String對象卻沒有這種功能(最近才有).對于沒有String.trim()方法的舊版瀏覽器,幾乎所有的JavaScript庫都提供了一種實現.
最常用的實現,類似如下代碼:
function trim(str){ return (str||"").replace(/^s+|s+$/g,""); } console.log(trim(" #id div.class ")==="#id div.class"); //true
參考資料:知道這 20 個正則表達式,能讓你少寫 1000 行代碼
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://m.specialneedsforspecialkids.com/yun/79400.html
摘要:特意對前端學習資源做一個匯總,方便自己學習查閱參考,和好友們共同進步。 特意對前端學習資源做一個匯總,方便自己學習查閱參考,和好友們共同進步。 本以為自己收藏的站點多,可以很快搞定,沒想到一入匯總深似海。還有很多不足&遺漏的地方,歡迎補充。有錯誤的地方,還請斧正... 托管: welcome to git,歡迎交流,感謝star 有好友反應和斧正,會及時更新,平時業務工作時也會不定期更...
摘要:值得一提的是每篇文章都是我用心整理的,編者一貫堅持使用通俗形象的語言給我的讀者朋友們講解機器學習深度學習的各個知識點。今天,紅色石頭特此將以前所有的原創文章整理出來,組成一個比較合理完整的機器學習深度學習的學習路線圖,希望能夠幫助到大家。 一年多來,公眾號【AI有道】已經發布了 140+ 的原創文章了。內容涉及林軒田機器學習課程筆記、吳恩達 deeplearning.ai 課程筆記、機...
閱讀 2229·2023-04-26 01:57
閱讀 3258·2023-04-25 16:30
閱讀 2334·2021-11-17 09:38
閱讀 1083·2021-10-08 10:14
閱讀 1392·2021-09-23 11:21
閱讀 3689·2019-08-29 17:28
閱讀 3459·2019-08-29 15:27
閱讀 952·2019-08-29 13:04