寫這篇文章不是空穴來風,最近一個禮拜寫了一個簡單的nodejs腳本,用來處理上千個文件,以便於在某些特定字符的周圍添加標記,先說一下我這個腳本使用場景主要是來識別中文(具體作什麼,以後會單獨寫一篇文章,此處只提該腳本做用),同時爲不一樣的文件類型,包括js,vm,jsp等等文件的中文周圍添加標記,以便於減小人工添加標記的事件。html
注:本文着重用示例講解,理論知識推薦此篇文章 http://www.jb51.net/tools/zhe... 最先我就是看的這篇文章初步接觸正則,正則剛開始很枯燥,慢慢學就行了,加油!!!前端
只是看下面的這些仍是處於懵逼狀態,其實直接看第二節例子便可,爲了完整性此處便於你們查閱!node
[]
集合{}
範圍()
分組|
並列關係+
一次或者屢次(範圍簡寫方式1)*
零次或屢次(範圍簡寫方式2)?
零次或一次(範圍簡寫方式3) 另外和貪婪模式有關,後面會講^
兩個功能,放在開始做爲開始符,放在[]
的開頭做爲「非」$
結束符\
轉義(?=pattern)
正向確定環視(這個名字好多地方都不同,斷言,預查,我最喜歡環視,同下)(?!pattern)
正向否認環視(?<=pattern)
逆向確定環視(?<!pattern)
逆向否認環視.
匹配除換行符以外的全部字符(此項如下爲範圍集)\s
匹配任何空白字符,包括空格、製表符、換頁符等等。\S
匹配任何非空白字符(s的反面)\d
匹配數字字符\D
匹配非數字字符(d的反面)\w
匹配字母、數字、下劃線\W
匹配非字母、數字、下劃線以上這些我以爲就是比較經常使用的基本可以夠你們使用的了,對於中文站通常還會用到中文的相關匹配,那麼中文的匹配爲[\u4e00-\u9fa5]
,其中\u
是四個十六進制數字表示的Unicode字符,不知道匹配的中文是否全,可是大部分還都是能夠的正則表達式
實際上調試正則能夠不須要什麼工具,你要非得要的話,能夠用Note Pad++
,這個簡單的編輯器內置有正則的匹配,Ctrl+F
彈出對話框裏邊是含有正則選擇項,打上對勾便可以在編輯其中寫內容,看看可否搜索到了。chrome
我建議看此篇文章或者練習的時候,在chrome
瀏覽器直接Windows
系統按F12
, Mac
上按command+option+J
,點擊console
或者控制檯
,用什麼瀏覽器自行研究如何打開控制檯,如圖後端
光標位置便可操做js,而後利用js的就能夠展現你寫的正則是否正確,很速度的方式,能夠用上下鍵來切換,迅速修改你的表達式數組
下文的Reg
表明正則表達式,str
表明要匹配的字符串,因爲還未開始正則表達式講解,若是有沒法理解請略讀,瞭解如何利用這幾個函數,而後開始進行第四節正則學習,而後回頭看就OK了。瀏覽器
testjsp
用法:Reg.test(str)
返回值:Boolean
實例:/a/.test("a")
// true編輯器
exec
用法:Reg.exec(str)
返回值:Array
或null
實例1:/b(a)/.exec("ba")
// ["ba", "a", index: 0, input: "ba"]
實例2:/a(c)/.exec("ba")
// null
解釋:匹配的值會按照順序-->全匹配,第一分組,第二分組...等等,匹配到的字符串位置(index),輸入的字符串(input)
match
用法:str.match(Reg)
返回值:Array
或null
其實和RegExp
的test
方法是一致的,只不過這個字符串在前
注意:當區分模式時match
返回狀況有所區別
實例1:"bababa".match(/b(a)/g)
// ["ba", "ba", "ba"]
實例2:"bababa".match(/b(a)/)
// ["ba", "a", index: 0, input: "bababa"]
search
用法:str.search(Reg)
返回值:Number
位置索引(無匹配返回-1)
實例:"wefeaba".search(/b(a)/)
// 5
split
用法:str.split(str)
或str.split(Reg)
【自動全局搜索】
返回值:Array
將分開的子字符串放到數組中
實例1:"前端,後端,設計".split(",")
// ["前端", "後端", "設計"]
實例2:"f4wef1er2gr".split(/\d/)
// ["f", "wef", "er", "gr"]
replace
用法:str.replace(str, str)
或str.replace(Reg,str)
或str.replace(Reg,Fn)
實例1:"前端,後端,設計".replace(",", "|")
// "前端|後端,設計"
實例2:"前端,後端,設計".replace(/,/, "|")
// "前端|後端,設計"
實例3:"前端,後端,設計".replace(/,/g, "|")
// "前端|後端|設計"
實例4:
"前端,後端,設計".replace(/,/g, function($all){ return '{' + $all + '}'; }); // "前端{,}後端{,}設計"
實例5:
"一、這是例子balabala".replace(/一、([\u4e00-\u9fa5]+)[a-z]*/g, function($all, $1){ return '{' + $1 + '}'; }) // "{這是例子}"
解釋: replace的函數參數順序爲-->全匹配,第一捕獲組,第二捕獲組...
邊練習邊寫,你會發現無窮的樂趣,看到中途累了休息一下
最簡單的正則
/a/
用途:匹配a,只要串中包含a便可
說明:js中用兩個/
來圈定正則,中間的a
即爲要匹配的字符
實例:/a/.test("ab")
// true
咱們如今看一個使用場景,你提供了一個輸入框,這個輸入框是讓用戶輸入手機號,先來個最簡單的規則,用戶的手機號應爲11位數字,這是一個最簡單的正則,以下所示。
/^\d{11}$/
用途:匹配從開始到結尾共11位數字的字符串
說明:^
用來標識開頭,$
用來標識結尾,\d
爲數字集合,{11}表明將\d
循環11次
注意:用來判斷某字符串正確與否必定要加開始結束標識符,看實例2便可看出端倪,十二位數字也被匹配上了,也就是隻要串中包含正則可匹配的就能成功,此處能夠看出開始結束符的重要性
實例1:/^\d{11}$/.test("13212344321")
// true
實例2:/\d{11}/.test("132123443211")
// true
/^\d{5,11}$/
用途:匹配從開始到結尾共5-11數字都可的字符串
說明:{5,11}
集合來標識5到11位,能夠{5,}
來表示5到n多位
實例1:/^d{5,11}$/.test("1234") // false
實例2:/^d{5,11}$/.test("1234567") // true
下面繼續拓展,組合上面方式
/^132\d{8}$/
用途:匹配開頭爲132的手機號碼
說明:132
其實就是直接匹配這三個字符,後面的其實就是動態匹配8位數字,合起來就是11位了
實例1:/^132\d{8}$/.test("18912344321")
// false
實例2:/^132\d{8}$/.test("13212344321")
// true
手機號不是隻有132開頭的啊,若是我想用189開頭的呢,請看
/^(132|189|133)\d{8}$/
用途:匹配開頭爲132或189或133的手機號
說明:此處應該注意咱們用到了分組()
和並列關係|
,並列就很簡單了就是說能夠132能夠189能夠133,此處必定注意分組是必定要用的若是不用就會出現實例1的狀況,由於並列關係不是前面數字了,變成了三部分了
實例1:/^132|189|133\d{8}$/.test("132")
// true
實例2:/^(132|189|133)\d{8}$/.test("132")
// false
實例3:/^(132|189|133)\d{8}$/.test("18912344321")
// true
實例4:/^(132|189|133)\d{8}$/.test("13212344321")
// true
如今來看另外一個場景,若是咱們不是判斷手機號,而是在一堆中文介紹中提取出手機號,那麼須要怎麼辦呢?
匹配內容:"你們好,我叫jackwang,個人手機號是{13212344321},他的手機號爲{13212344321}測試"
/\{((132|189|133)\d{8})\}/
用途:用來匹配文中的手機號,注意手機兩邊有標識{
和}
咱們有這個定位符會很方便將其匹配出來
說明:首先,能夠看到\{
,咱們前面提到了{
和}
爲正則特殊字符,雖然此處不加也能夠,可是好習慣就是特殊字符要加上\
避免出問題,例如{1}
,若是你要匹配的不是前面的東西循環一次那麼就會出問題了;另外,看到我用兩個()
這至關於有兩個捕獲組,請看實例(這回我用exec,會看的更直接)
實例1:/\{((132|189|133)\d{8})\}/.exec("你們好,我叫jackwang,個人手機號是{13212344321},他的手機號爲{13212344321}測試")
// ["{13212344321}", "13212344321", "132", index: 21, input: "你們好,我叫jackwang,個人手機號是{13212344321},他的手機號爲{13212344321}測試"]
能夠看到第一捕獲組放在了索引爲1的位置,咱們就能夠直接取用了,不過咱們會想若是串中若是有多個電話號想搞怎麼辦,就像上面這段字符串,下面我給出js寫法,並解釋
var str = "你們好,我叫jackwang,個人手機號是{13212344321},他的手機號爲{13212344334}測試"; var reg = /\{((132|189|133)\d{8})\}/g; console.log(reg.exec(str)); console.log(reg.exec(str)); // ["{13212344321}", "13212344321", "132", index: 21, input: "你們好,我叫jackwang,個人手機號是{13212344321},他的手機號爲{13212344334}測試"] // ["{13212344334}", "13212344334", "132", index: 41, input: "你們好,我叫jackwang,個人手機號是{13212344321},他的手機號爲{13212344334}測試"]
說明:g
正則後面加個g
表示全局模式;關於模式,i
表示不區分大小寫,m
表示多行模式,我不多用,此處不講了;對於exec
有這麼個特性,當正則表達式爲全局匹配模式
每次執行exec
後會刷新下一次執行開始位置,下一次的開始位置爲第一次匹配的最後一個字符的下一個位置,因此執行兩次就會將串中全部的匹配出來,這樣就實現了提取的目的
繼續看上面的這段文本,若是我想匹配jackwang
怎麼辦呢?
/[acgjknw]+/
用途:匹配包含acgjknw這些字符的1或屢次循環
說明:[]
是字符集,裏邊的就是要表示的字符,後面加一個+
那麼就是表示將前面的[]
裏邊的循環1次或屢次,同理?
和*
再也不用例子展現了
實例:/[acgjknw]+/g.exec("你們好,我叫jackwang,個人手機號是{13212344321},他的手機號爲{13212344334}測試")
// ["jackwang", index: 6, input: "你們好,我叫jackwang,個人手機號是{13212344321},他的手機號爲{13212344334}測試"]
能夠看到咱們寫了不少字母,其實咱們想匹配英文名,英文名不必定只有這幾個字符,因此此處咱們能夠這樣
/[a-z]+/
用途:匹配包含a-z的1或屢次循環
說明:注意-
這是範圍的意思,按照ASCII
中的順序,寫這個範圍就行,這回我搞腳本的時候就遇到一個坑,如實例2,原本想匹配:-=,可是忘記對-進行轉義,致使<也被匹配上
實例1:/[a-z]+/g.exec("你們好,我叫jackwang,個人手機號是{13212344321},他的手機號爲{13212344334}測試")
// ["jackwang", index: 6, input: "你們好,我叫jackwang,個人手機號是{13212344321},他的手機號爲{13212344334}測試"]
實例2:/[:-=]/.test("<")
// true
還有一些什麼沒講呢,下面單獨舉例來講明
貪婪模式/非貪婪模式
字符串:"baeabaeab"
/b[a-z]+b/
和/b[a-z]+?b/
說明:前者爲貪婪模式,後者爲非貪婪模式;請注意+
後面的?
添加了就爲非貪婪模式,同理*
和'?'後面能夠添加;貪婪模式就是屢次循環會盡量的去匹配,非貪婪模式就是最少匹配,看實例結果便可明白,此正則功能頗有用但願你們記住
實例1:/b[a-z]+b/.exec("baeabaeab")
// ["baeabaeab", index: 0, input: "baeabaeab"]
實例2:/b[a-z]+?b/.exec("baeabaeab")
// ["baeab", index: 0, input: "baeabaeab"]
反義
/[^5]/
說明:只要在集合的最開始用^
便可,就是表示除了5以外全部字符
實例:/[^5]/.test("5")
// false
環視
環視其實某些狀況仍是挺好用的,還記得前面的匹配手機號嗎?
字符串: "你們好,我叫jackwang,個人手機號是{13212344321},他的手機號爲13212344334測試"
其實咱們還能夠用環視
/(?<=\{)((132|189|133)\d{8})(?=\})/
實例:/(?<=\{)((132|189|133)\d{8})(?=\})/.exec("你們好,我叫jackwang,個人手機號是{13212344321},他的手機號爲13212344334測試")
// ["13212344321", "13212344321", "132", index: 22, input: "你們好,我叫jackwang,個人手機號是{13212344321},他的手機號爲13212344334測試"]
說明:剛開始環視可能比較難以理解,我通俗點講,我以爲比我最開始提到的文章好理解
(?<=\{)
爲逆向確定環視,舉例來講,在匹配132
以前要從1往回看,也就是逆向看看他的上一位是否是{
,若是是的話纔算合法,若是不是就匹配不成功,也就是你要往前看不是張三,那我就不找你了。同理,(?=\})
爲正向確定環視,也就是匹配手機號以後,後面必定要有}
,這樣纔算成功,也就是你向後(順序)看是李四才行,這整個表達式也就是你向前(逆向)看必須是張三,向後(正向)看必須是李四,我纔會找你。(?<!pattern)
逆向否認環視,(?!pattern)
正向否認環視, pattern爲要匹配的表達式,舉個例子/(?<!\{)((132|189|133)\d{8})(?!\})/
說明:匹配手機號前面沒有{
後面沒有}
的手機號
實例2:/(?<!\{)((132|189|133)\d{8})(?!\})/.exec("你們好,我叫jackwang,個人手機號是{13212344321},他的手機號爲13212344334測試")
// ["13212344334", "13212344334", "132", index: 41, input: "你們好,我叫jackwang,個人手機號是{13212344321},他的手機號爲13212344334測試"]
綜上,看出來這兩個實例的不一樣了嗎,固然你能夠任意匹配這四種方式來達到你要的效果;可是注意,可能每種語言支持程度不一樣,不要過分依賴。
匹配任意字符建議使用 /[\s\S]+/
由於.
會去掉換行符
注意用到的特殊字符必定要轉義(好習慣) /[\{\}\[\]\^\$]/
注意-
的使用 /[:-=]/
這樣會匹配<
等,注意轉義
運算符優先級
運算符 | 描述 |
---|---|
\ | 轉義 |
()[] | 圓括號和方括號 |
*, +, ?, {n}, {n,}, {n,m} | 限定符 |
^, $, 任何元字符、任何字符 | 定位點和序列 |
| | 或操做 |
關於那些js的處理函數,本身去摸索吧,篇幅這麼長,估計要看不下去了,我搞腳本的時候大量使用了replace
和test
函數,很好用,對於文件總體處理操做很好用,建議好好學學,請見MDN:https://developer.mozilla.org...
可能還有其餘一些沒講到的正則知識,可是上面的這些基本包含了正則的90%了。
囉裏囉嗦講了這麼久,只是爲了讓新手可以由淺入深的慢慢學習,學習正則不是一蹴而就的過程,須要慢慢使用,慢慢探索,同一個匹配可能能寫出好多正則,你們能夠慢慢練習,寫出更優雅的正則。
另外要說一點,不是非要寫一個巨長的正則來匹配巨難的字符串,要合理利用各語言的函數來簡化正則的寫法,不然一個巨長的正則可能就是噩夢,這個事本身權衡,相信會將正則用到極致。
謝謝!
本文若有疏漏之處或者又問題交流,請直接回複本文!