開發之正則表達式的語法詳解
正則表達式
序言
好久沒寫過文章啦,距離自己上一次的記錄已經過去了半年多了,也許是工作忙了,也許是自己懶惰了,也許是...最近的工作不怎么忙,心就想著要寫點什么呢,由于同事的幾句話,真的"機緣巧合"的寫了這個知識,雖然這個知識點有點陳舊哈,但我相信對于那些對正則剛入門初學的開發者來說,你認真看過這篇文章之后,對于正則的認識、語法規則必會有一個大大提升的,若再附加自己的實踐,相信你對于掌握好這個知識點是沒有什么問題的哈,:grin:
含義
是由普通字符(字符 a 到 z)以及特殊字符("元字符")組成的文字模式(即字符串文本的復雜處理(查找、匹配、驗證))
核心
正則表達式的語法規則
原則
盡可能羅列出所有出現的情況,然后再按照羅列的字符串寫出符合要求的正則表達式,盡可能的精確匹配
建議
雖然現在常見的正則表達式我們都可以查到,但還是應該對正則語法有一些認識,不可生搬硬套別人的正則表達式
普通字符
包括沒顯式指定為元字符的所有可打印和不可打印字符(所有大寫和小寫字母、所有數字、所有標點符號和一些其他符號)
特殊字符
若匹配這些特殊字符,須先使用轉義字符``放在它們前面
幾點說明
- 匹配包括 '\n' 在內的任何單字符 - [.\n]
- 選擇符 | 一般結合非捕獲元字符 ?: 和分組 () 搭配使用,因為它的優先級最低
- 分組 () 是對于復雜的文本分割成子表達式使用,一般結合反向引用 \n 使用,這時編號是按照左括號往右的一次疊加的,即:編號從 1 開始,最多可存儲 99 個捕獲的子表達式,場景: 匹配重復出現的字符串
- 中括號表達式(字符簇) [] ,表示所有字符的字符簇(集合),若在中括號表達式中包括連字符 - ,則需要用反斜扛將它轉義,但是若將連字符放在中括號列表的開始或結尾,則不需反斜扛轉義
非打印字符
下圖列出了非打印字符的轉義序列
限定符
限定符用來指定正則的一個子表達式出現多少次能滿足匹配,共6種
幾點說明
- 限定符 * 、 + 、 ? 都是貪婪的,它們會盡可能多的匹配所搜索的字符串,只有在它們的后面加上一個 ? 就可以實現非貪婪或最小匹配
- 即: ? 放在任何一個其他限定符 ( * , + , ? , {n} , {n,} , {n,m} ) 后面時,匹配模式是非貪婪的,非貪婪模式會盡可能少的匹配所搜索的字符串(比如:對于字符串 "chongzoneeeee",'e+?' 將匹配單個 "e",而 'e+' 將匹配所有 'e'),場景:檢測字符串是否包含某個字符等
定位符
定位符使您能夠將正則固定到行首或行尾
注意點
不能將限定符與定位符一起使用,因為在緊靠換行或字邊界的前面或后面不能有一個以上位置
預搜索(零寬斷言assert)
零寬斷言是對位置的匹配,共4種(下圖列出了常見的2種)
幾點說明
- (?:pattern) - 分組雖然使匹配更加清晰,但同時會產生一個副作用,使相關的匹配被緩存(存儲到一個臨時緩沖區中),此時使用 ?: 放在分組選項前可消除這種副作用,不捕獲匹配的文本,即:不給分組分配組號,則此時對于重復的字符串就不能使用反向引用
- (?=pattern) - 匹配以pattern結尾的前面的部分字符串,不包括pattern部分
- (?<=pattern) - 匹配以pattern開頭的后面的部分字符串,不包括pattern部分
- (?!pattern) - 斷言位置的后面不能匹配表達式pattern
- (?<!pattern) - 斷言位置的前面不能匹配表達式pattern
即: (?=pattern) 和 (?!pattern) 放在后面, (?<=pattern) 和 (?<!pattern) 放在前面,場景: 取出需要的字符串
反向引用
反向引用用于重復搜索前面某個分組匹配的子表達式,當然也可以自己指定子表達式的組名
語法規則
(?<name>\w+)(或':(?'name'\w+)) ,這樣組名\w+的就定為 name ,若是反向引用這個分組,則使用 \k<name> ,即: \b(?<name>\w+)\b\s+\k<name>\b
其他元字符
不常用的其他元字符
- 模式修改符 - (?i) 開 和 (?-i) 關 - 包含區域不區分大小寫 - 不建議使用
- 注釋 - (?#comment) ,對于不熟悉的匹配規則可以使用
運算符的優先級
下表從上到下列出了優先級最高到最低的排序
常用的正則表達式
寫到這里的時候,自己呢本是不想寫這個常用正則表達式部分的,但基于我看到的其他開發者寫的或歸納整理的正則表達式,大部分都是COPY下來的,里面的有些正則表達式明顯是有錯誤的...這樣傳閱下來估計會誤導不少初學者呢,雖然對客戶端開發者來說,正則使用的不是很頻繁,在開發中用到的也就那么幾種,現在的互聯網這么發達,百度谷歌下不就知道啦,當然了還有另一個原因,由于正則的語法比較繁瑣,時間一長不經常使用的話難免有些正則會被遺忘的,這樣整理的話自己以后使用也是很方便的,好記性比不上爛筆頭嘛,哈哈,廢話就不多說了,有什么寫的不對的地方請多多交流哈??(ノへ ̄、)
1.用戶名(首字母,長度6-16)
"^[a-zA-Z]\\w{5,15}$"
2.表單密碼(長度6-16)
"^\\.{6,16}$"
3.驗證碼(長度6)
"^\\d{6}$"
4.固話號碼(首數字0)
"^0\\d{2,3}-\\d{7,8}$"
5.手機號碼(長度11)
"1|[34578]\\d{9}"
6.身份證號(長度18,長度15已淘汰)
"^\\d{17}[\\dxX]$"
7.Email地址(.com、.cn等)
"^\\w+@\\w+(\\.[a-zA-Z]{2,3}){1,2}$"
8.僅含數字
"^\\d+$”
9.僅含字母
"^[a-zA-Z]+$"
10.僅含數字和字母
"^[0-9a-zA-Z]+$"
11.整數
"^\\-?\\d+$"
12.小數
"^\\d+\\.\\d*$"
13.浮點數
"^\\-?\\d+\\.?\\d*$"
14.正整數(最小1)
"^\\+?[1-9]+$"
15.負整數(最大-1)
"^\\-[1-9]+$"
16.n位的小數
"^\\d+\\.\\d{n}$"
17.月份(長度1\2)
"^(0?[1-9]|1[0-2])$"
18.日數(最大31)
"^((0?[1-9])|((1|2)[0-9])|30|31)$"
19.含空白行
"\\s*"
20.首位空白符
"^\\s+|\\s+$"
21.含雙字節
"[^\x00-\xff]"
22.包含中文(檢測工具不支持)
"[\\u4e00-\\u9fa5]+"
23.搜索疊詞
"\\b([a-z]+) \1\\b"
24.含n個字母的單詞
"[[:alpha:]]{n}"
25.中國郵編(長度6)
"^[1-9]\\d{5}$"
26.QQ號碼(最小5位,目前最大10位)
"^[1-9]\\d{5}$"
27.HTML標簽
"<\\s*(\\S+)(\\s[^>]*)?>[\\s\\S]*<\\s*\\/\\1\\s*>"
28.網絡URL(附帶端口號匹配)
"http(s?):\\/\\/([^\\/:]+)(:\\d*)?([^ ]*)"
29.網頁圖片
"\\< *[img][^\\\\>]*[src] *= *[\\"\\']{0,1}([^\\"\\'\\ >]*)"
30.IP地址
"^(([01]?\\d\\d?|2[0-4]\\d|25[0-5])\.){3}([01]?\\d\\d?|2[0-4]\\d|25[0-5])$"
iOS開發中的使用
在iOS開發中, Cocoa框架 給我們提供了謂詞 NSPredicate 類,類似過濾器的作用,就相當于 SQL 的 where 條件,在iOS開發中,我們常用的做法將謂詞和正則表達式配合使用,代碼如下:
/**
- 匹配字符串
@param inputText 輸入的文本
@param validRegular 正則表達式
@return YES 匹配成功 NO 匹配失敗/
- (BOOL)verifysInputText:(NSString )inputText validRegular:(NSString )validRegular {
NSPredicate *predicte = [NSPredicate predicateWithFormat:@"SELF MATCHES %@",validRegular];
return [predicte evaluateWithObject:inputText];
}</pre>
結束語
最后呢,推薦給大家一個在線的正則表達式檢測工具 Regex101 ,當然在Mac端,你也可以下載一個客戶端 RegExRx ,不過它不是免費的,需要30塊大洋,但它的界面簡潔,為了學習嘛,都懂的,當然你也可以下載個破解版...:grin:
(ps:在檢測工具內,單斜杠 不需要轉為雙斜杠 \ ,因為只有在代碼中,編譯器是默認單斜杠為轉義字符,需要你轉為雙斜杠,所以上面你 看到的代碼全是雙斜杠的 \`,還有就是基本常見的檢測工具都是不支持檢測中文輸入的,因為不能識別 "\u" 字符)
對于這個知識點、文章有什么不太理解的地方,還請在下面留言,看到之后有時間會回復的... 午安。。。
Regex101測試工具
RegExRx測試工具
來自:https://juejin.im/entry/58ca26c3570c3500588ec9a6
- (BOOL)verifysInputText:(NSString )inputText validRegular:(NSString )validRegular {
NSPredicate *predicte = [NSPredicate predicateWithFormat:@"SELF MATCHES %@",validRegular];
return [predicte evaluateWithObject:inputText];
}</pre>