這篇文章其實是在學習正則表達式時網(wǎng)上一些資料的整合,所以只能算是一個總結性文章,不是自己原創(chuàng),感謝各位的分享。參考文章和網(wǎng)站在文章結尾。
1.概念
正則表達式:描述符合某些規(guī)則字符串的工具。
正則表達式經(jīng)常用于匹配符合規(guī)則的字符串,然后對符合規(guī)則的字符串進行處理。
在iOS中常用的場景包括:輸入框內輸入內容的限制,特定文本的判定(比如手機號、郵箱、密碼等),對文本內特定字符進行搜索,進行富文本化或替換等。
2.基本規(guī)則
正則表達式基本上由一些特定的字符和表達式構成,所以理解這些字符或表達式是學習的基礎。
元字符:
表1.常用元字符
代碼 | 說明 |
---|---|
. | 匹配出換行符意外的任意字符 |
\w | 匹配字母或數(shù)字或下劃線或漢字 |
\s | 匹配任意的空白符 |
\d | 匹配數(shù)字 |
\b | 匹配單詞的開始或結束(不匹配標點符號或者換行符,只匹配一個位置) |
^ | 匹配字符串的開始 |
$ | 匹配字符串的結束 |
字符轉義:
如果想使用元字符本身的話,需要用轉義字符,即\*表示*字符。
反義:
有時候需要查找不屬于某個簡單定義的字符類的字符。比如想查找除了數(shù)字以外,其它任意字符都行的情況,這時需要用到反義。
表2.常用反義符號
代碼/語法 | 說明 |
---|---|
\W | 匹配任意不是字母、數(shù)字、下劃線、漢字的字符 |
\S | 匹配任意不是空白符的字符 |
\D | 匹配任意非數(shù)字的字符 |
\B | 匹配不是單詞開頭或結束的位置 |
[^x] | 匹配除了x以外的任意字符 |
[^aeiou] | 匹配除了aeiou這幾個字母以外的任意字符 |
重復:
表3.常用的限定符
代碼/語法 | 說明 |
---|---|
* | 重復零次或者更多次 |
+ | 重復一次或者更多次 |
? | 重復零次或一次 |
{n} | 重復n次 |
{n,} | 重復n次或更多次 |
{n,m} | 重復n到m次 |
范圍:
自定義匹配集合使用[]。比如數(shù)字范圍[0-9]。
分支條件:
如果有幾種規(guī)則,滿足其中任意一種都應當匹配。不同的規(guī)則用 | 隔開,這就是分支條件。
匹配分支條件時,會從左到右的測試每個條件,如果滿足了某個分支的話,就不會再管其他條件。
分組:
可以用()小括號來指定子表達式(即分組)??梢詫Ψ纸M進行重復。
捕獲:
默認情況下每個分組會自動擁有一個組號,從左到右,從1開始。可以用\1代表分組1匹配的文本。
可以使用(?<name>exp)來指定組名,并用\k<name>來捕獲。
零寬斷言
零寬斷言是指定滿足一定條件(即斷言)的位置。
負向零寬斷言:如果我們只是想要確保某個字符沒有出現(xiàn),但并不想去匹配它時就可以使用負向領寬斷言,因為它只匹配一個位置,并不消費任何字符。
注釋
要包含注釋的話最好啟用“忽略模式里的空白符”選項。這樣在#后面到這一行結束的所有文本都將被當成注釋忽略掉。
比如:
(?<= # 斷言要匹配的文本的前綴
<(\w+)> # 查找尖括號括起來的字母或數(shù)字(即HTML/XML標簽)
) # 前綴結束
.* # 匹配任意文本
(?= # 斷言要匹配的文本的后綴
<\/\1> # 查找尖括號括起來的內容:前面是一個"/",后面是先前捕獲的標簽
) # 后綴結束
貪婪與懶惰
當正則表達式中包含能接受重復的限定服時,通常的行為是(在使整個表達式能得到匹配的前提下)匹配盡可能多的字符。這被稱為貪婪匹配。
而懶惰匹配與此相反,在能使整個匹配成功的前提下匹配盡可能少的字符。
表5.懶惰限定符
代碼/語法 | 說明 |
---|---|
*? | 重復任意次,但盡可能少重復 |
+? | 重復一次或更多次,但盡可能少重復 |
?? | 重復0次或1次,但盡可能少重復 |
{n,m}? | 重復n到m次,但盡可能少重復 |
{n,}? | 重復n次以上,但盡可能少重復 |
處理選項
一般會有正則表達式的處理選項,比如:忽略大小、忽略空白、顯示捕獲等,根據(jù)開發(fā)環(huán)境的不同會有不同選項,注意選擇使用。
平衡組/遞歸匹配
- (?'group')把捕獲的內容命名為group,并壓入堆棧(Stack)
- (?'-group')從堆棧上彈出最后壓入堆棧的名為group的捕獲內容,如果堆棧本來為空,則本次匹配失敗
- (?(group)yes|no)如果對戰(zhàn)上存在以名為group的內容的話,繼續(xù)匹配yes內容,否則匹配no內容
- (?!)零寬負向先行斷言,由于沒有后綴表達式,視圖匹配總是失敗
平衡組常見的應用是匹配HTML。
例子:匹配<>成對出現(xiàn)的字符串。
< #最外層的左括號
[^<>]* #最外層的左括號后面的不是括號的內容
(
(
(?'Open'<) #碰到了左括號,在黑板上寫一個"Open"
[^<>]* #匹配左括號后面的不是括號的內容
)+
(
(?'-Open'>) #碰到了右括號,擦掉一個"Open"
[^<>]* #匹配右括號后面不是括號的內容
)+
)*
(?(Open)(?!)) #在遇到最外層的右括號前面,判斷黑板上還有沒有沒擦掉的"Open";如果還有,則匹配失敗
> #最外層的右括號
3.常用正則表達式
說明 | 正則表達式 | |
---|---|---|
手機號 | ^((13[0-9])|(15[012356789])|(17[0,0-9])|(18[0,0-9]))\d{8}$ | |
郵箱 | ^([a-z0-9_.-]+)@([\da-z.-]+).([a-z.]{2,6})$ | |
身份證 | [1-9]\d{5}(18|19|([23]\d))\d{2}((0[1-9])|(10|11|12))(([0-2][1-9])|10|20|30|31)\d{3}[0-9Xx]$)|([1-9]\d{5}\d{2}((0[1-9])|(10|11|12))(([0-2][1-9])|10|20|30|31)\d{2}$ | |
短信驗證碼 | \d{6} | |
中文字符 | [\u4e00-\u9fa5] | |
用戶名 | ^[a-z0-9_-]{3,16}$ | |
密碼 | ^[a-z0-9_-]{6,18}$ | |
QQ號 | [1-9][0-9]{4,} | |
國內電話 | \d{3}-\d{8} | \d{4}-\d{7} |
URL | ^(https?://)?([\da-z.-]+).([a-z.]{2,6})([/\w .-]*)*/?$ | |
IP | ^(?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?).){3}(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)$ |
可以點擊下面網(wǎng)址查看更多正則表達式常用正則表達式,使用之前自己最好再驗證一下,有一些也不一定準確。
4.正則表達式在iOS中的應用
iOS中正則表達式有三種使用方式
1). 利用NSPredicate(謂詞)匹配
例如郵箱匹配 :
NSString *email = @"niji_saki@163.com";
NSString *regex = @"^([a-z0-9_\.-]+)@([\da-z\.-]+)\.([a-z\.]{2,6})$";
NSPredicate *predicate = [NSPredicate predicateWithFormat:@"SELF MATCH %@", regex];
BOOL isValid = [predicate evaluateWithObject:email];
2). 利用rangeOfString:option:直接查找
NSString *searchText = @"http:// Do any additional setup after loading the view, typically from a nib.";
NSRange range = [searchText rangeOfString:@"(?:[^,])*\\." options:NSRegularExpressionSearch];
if (range.location != NSNotFound) {
NSLog(@"%@", [searchText substringWithRange:range]);
}
3).使用正則表達式類
NSString *searchText = @"http:// Do any additional setup after loading the view, typically from a nib.";
NSError *error = NULL;
NSRegularExpression *regex = [NSRegularExpression regularExpressionWithPattern:@"(?:[^,])*\\." options:NSRegularExpressionCaseInsensitive error:&error];
NSTextCheckingResult *result = [regex firstMatchInString:searchText options:0 range:NSMakeRange(0, [searchText length])];
if (result) {
NSLog(@"%@\n", [searchText substringWithRange:result.range]);
}
第一種需要學習NSPredicate的寫法,第二種之關心匹配結果,第三種效率最高。
5. NSRegularExpression詳解
NSRegularExpression是一個用于匹配Unicode字符串的正則表達式類,該類不可變(immutable)。
NSRegularExoression的基本方法是在目標字符串符合正則表達式是調用一個block,這個block中含有匹配結果信息。此外還有其他一些方法在匹配后返回諸如數(shù)組、匹配數(shù)量、匹配范圍、第一次匹配等結果。還有用來匹配后替換字符串的方法。
匹配結果放在NSTextCheckingResult類中,該類中包含匹配的范圍、數(shù)量、結果類型等變量(iOS11 中新增了rangWithName的方法),同時也提供一些特定的匹配方法,比如針對手機號、日期、地址等的匹配。
NSRegularExpression支持的正則表達式標準在該網(wǎng)站.
具體接口,參見蘋果官方的API。需要注意的是:
- 當沒有匹配到內容時,返回的range值為{NSNotFound,0}。
- 當匹配到的內容有多個時,NSTextCheckingResult的range返回匹配內容范圍,range:at:返回匹配內容中的每一個字符的匹配范圍。
- 匹配方法enumerateMatches(in:options:range:using:) 會根據(jù)options來確定block調用方式,在block中可以設置bool來決定是否停用匹配。
- stringByReplacingMatchesInString:options:range:withTemplate:方法,template參數(shù)使用$0可以代表匹配的全部字符,使用$1代表第一個字符,依次類推。
- NSRegularExpression是不可變和線程安全的,因此一個實例可以用在多個線程中進行匹配操作,然而被匹配的字符串在匹配過程是應該是不可變的。
6. iOS正則表達式開源庫
[1].30分鐘了解正則表達式
[2].iOS中正則表達式的三種使用方式