iOS正則表達(dá)式探索

參考:正則表達(dá)式正則表達(dá)式30分鐘入門教程、正則表達(dá)式的使用方法

一、概述

正則表達(dá)式(Regular Expression)是一種文本模式,包括普通字符(例如,a 到 z 之間的字母)和特殊字符(稱為“元字符”)。

正則表達(dá)式使用單個(gè)字符串來描述、匹配一系列匹配某個(gè)句法規(guī)則的字符串。

正則表達(dá)式是繁瑣的,但它是強(qiáng)大的,學(xué)會(huì)之后的應(yīng)用會(huì)讓你除了提高效率外,會(huì)給你帶來絕對的成就感。

二、簡介

除非您以前使用過正則表達(dá)式,否則您可能不熟悉一些術(shù)語。但是,毫無疑問,您已經(jīng)使用過不涉及腳本的某些正則表達(dá)式概念。
例如,您很可能使用?*通配符來查找硬盤上的文件。?通配符匹配文件名中的0個(gè)或單個(gè)字符,而 *通配符匹配零個(gè)或多個(gè)字符。像 data?.dat這樣的模式將查找下列文件:

data1.dat
data2.dat
datax.dat
dataN.dat


使用*字符代替 ? 字符擴(kuò)大了找到的文件的數(shù)量。data*.dat 匹配下列所有文件:

data.dat
data1.dat
data2.dat
data12.dat
datax.dat
dataXYZ.dat
ps:在OC中的結(jié)果,
`data?.dat `匹配
dat.dat
data.dat
datfdat
datagdat

`data*.dat `匹配
dat.dat
data.dat
dataa.dat
dataaa.dat
datfdat
datagdat
datahdat
我主要想說明的是.匹配任意字符
*匹配的是數(shù)量上0個(gè)或者多個(gè)(也就是說,可以沒有,可以有一個(gè),也可以有多個(gè))
?匹配的是數(shù)量上0個(gè)或者是1個(gè)(也就是可以也可以沒有)

盡管這種搜索方法很有用,但它還是有限的。通過理解 * 通配符的工作原理,引入了正則表達(dá)式所依賴的概念,但正則表達(dá)式功能更強(qiáng)大,而且更加靈活。
正則表達(dá)式的使用,可以通過簡單的辦法來實(shí)現(xiàn)強(qiáng)大的功能。下面先給出一個(gè)簡單的示例:

^[0-9]+abs$

  • ^ 為匹配輸入字符串的開始位置。
  • [0-9]+匹配多個(gè)數(shù)字,[0-9] 匹配單個(gè)數(shù)字,+匹配一個(gè)或者多個(gè)。
  • abc$匹配字母 abc 并以 abc 結(jié)尾,$ 為匹配輸入字符串的結(jié)束位置。

示例:
匹配以數(shù)字開頭,并以abc結(jié)尾的字符串。:

var str = "123abc";
var patt1 = /^[0-9]+abc$/;
document.write(str.match(patt1));

以下標(biāo)記的文本是獲得的匹配的表達(dá)式:

123abc

ps:這只是在文件搜索系統(tǒng)中的正則看,在iOS中則略有不同,所以不要在OC中測試上述正則

為什么要使用正則表達(dá)式?

典型的搜索和替換操作要求您提供與預(yù)期的搜索結(jié)果匹配的確切文本。雖然這種技術(shù)對于靜態(tài)文本執(zhí)行簡單的搜索和替換任務(wù)已經(jīng)足夠了,但它缺乏靈活性,若采用這種方法搜索動(dòng)態(tài)文本,即使不是不可能,至少也會(huì)變得很困難。

通過正則表達(dá)式,可以:

  • 測試字符串內(nèi)的模式:
    例如,可以測試輸入字符串,以查看字符串是否出現(xiàn)電話號(hào)碼模式或信用卡號(hào)碼模式。這稱為數(shù)據(jù)驗(yàn)證。

  • 替換文本。
    可以使用正則表達(dá)式來識(shí)別文檔中的特定文本,完全刪除該文本或者用其他文本替換它。

  • 基于模式匹配從字符串中提取子字符串。
    可以查找文檔內(nèi)或者輸入域內(nèi)特定的文本。

例如,您可能需要搜索整個(gè)網(wǎng)站,刪除過時(shí)的材料,以及替換某些HTML格式標(biāo)記。在這種情況下,可以使用正則表達(dá)式來確定在每個(gè)文件中是否出現(xiàn)該材料或該HTML格式標(biāo)記。此過程將受影響的文件列表縮小到包含需要?jiǎng)h除或更改的材料的那些文件。最后,可以通過正則表達(dá)式來搜索和替換標(biāo)記。

三、正則表達(dá)式的語法

下面描述了正則表達(dá)式用于匹配字符串中的模式的字符表達(dá)式,制定模式匹配多少次的模式運(yùn)算符和其他匹配限制,最后一個(gè)表指定可以包含在正則表達(dá)式中的標(biāo)志通過多行指定搜索行為的模式(也可以使用選項(xiàng)標(biāo)志來指定這些標(biāo)志)

表1描述了用于匹配字符串中的字符的字符序列

表格1正則表達(dá)式元字符
字符表達(dá) 描述
\a 匹配BELL, \u0007
\A 在輸入開始時(shí)匹配。不同于^在\A輸入中的一個(gè)新行之后將不匹配。
\b, outside of a [Set] 如果當(dāng)前位置是字邊界匹配。邊界發(fā)生word(\w)和非word(\W)字符之間的轉(zhuǎn)換處,組合標(biāo)記被忽略。為了更好的字邊界,請參閱。NSRegularExpressionUseUnicodeWordBoundaries
\b, within a [Set] 匹配退格,\u0008。
\B 如果當(dāng)前位置不是字邊界匹配。
\cX 匹配一個(gè)control-X字符
\d 匹配任何字符與Unicode通用類別的Nd(數(shù)字,十進(jìn)制數(shù)字)
\D 匹配任何不是十進(jìn)制數(shù)字的字符。
\e 匹配ESCAPE,\u001B。
\E 終止\Q ... \E引用的序列。
\f 匹配一個(gè)form feed,\u000C。
\G 如果當(dāng)前位置在上一個(gè)匹配結(jié)束時(shí)匹配。
\n 匹配LINE FEED,\u000A。
\N{UNICODE字符名稱} 匹配named character。
\p{UNICODE PROPERTY NAME} 使用指定的Unicode屬性匹配任何字符。
\P{UNICODE PROPERTY NAME} 匹配任何不具有指定Unicode屬性的字符。
\Q 行情所有后續(xù)字符,直到\E。
\r 匹配運(yùn)送返回,\ u000D。
\s 匹配一個(gè)空白字符??崭癖欢x為[\ t \ n \ f \ r \ p {Z}]。
\S 匹配非空白字符。
\t 匹配水平制表符,\u0009。
\uhh 匹配字符與十六進(jìn)制值hh
\Uhhhhhhhhh 匹配字符與十六進(jìn)制值hhhhhhhhhh。必須提供8位十六進(jìn)位數(shù)字,即使是最大的Unicode代碼點(diǎn)\U0010ffff
\w 匹配一個(gè)字符 字符是[\ p {L1} \ p {Lu} \ p {Lt} \ p {Lo} \ p {Nd}]。
\W 匹配非字詞。
\x{hhhh} 匹配字符與十六進(jìn)制值hhhh。可提供1到6個(gè)十六進(jìn)制數(shù)字。
\x 匹配字符與兩位十六進(jìn)制值hh
\X 匹配一個(gè)化身集群
\Z 如果當(dāng)前位置在輸入結(jié)束處,而在最后一行終止符之前,則匹配,如果存在。
\z 如果當(dāng)前位置在輸入結(jié)束時(shí)匹配。
\n 返回參考。匹配任何第n個(gè)捕獲組匹配。n必須是模式中的數(shù)字≥ 1和≤總數(shù)量的捕獲組。
\0ooo 匹配八進(jìn)制字符 ooo是從一到三個(gè)八進(jìn)制數(shù)字。0377是最大允許的八進(jìn)制角色。領(lǐng)先的零是必需的; 它將八進(jìn)制常數(shù)與反向引用區(qū)分開來。
[pattern] 匹配模式中的任何一個(gè)字符。
. 匹配任何角色 見并且在字符表達(dá)式表4。NSRegularExpressionDotMatchesLineSeparators
^ 在一行開始匹配 見并且在字符表達(dá)式表4。NSRegularExpressionAnchorsMatchLines\m
$ 在一行結(jié)束時(shí)匹配。見并且在字符表達(dá)式表4。NSRegularExpressionAnchorsMatchLines
引用以下字符。必須引用被視為文字的字符是* ? + [ ( ) { } ^ $ \ . /

正則表達(dá)式運(yùn)算符

表2正則表達(dá)式運(yùn)算符
操作 描述
交替 (甲 乙)要么匹配甲或乙。
* 0或者是更多次數(shù)的匹配
+ 1或更多次 匹配盡可能多的次數(shù)。
? 匹配零次或一次
{n} 完全匹配n次
{n,} 至少匹配n次 匹配盡可能多的次數(shù)。
{n ,m} n和m之間的匹配。匹配盡可能多的次數(shù),但不能超過m。
*? 匹配0或更多次 匹配盡可能少的次數(shù)。
+? 比賽1次以上 匹配盡可能少的次數(shù)。
?? 匹配零次或一次。更偏好零。
{n}? 完全匹配n次
{n,}? 匹配至少n次,但不超過整體模式匹配所需。
{n,m}? n和m之間的匹配。匹配次數(shù)盡可能少,但不小于n。
*+ 匹配0次以上。在第一次遇到時(shí),盡可能多地匹配,即使整體匹配失?。≒ossessive Match)也不要重試。
++ 匹配一次以上 possessive match
?+ 匹配零次或一次。possessive match
{n}+ 完全匹配n次
{n,}+ 至少匹配n次possessive match
{n,m}+ n和m之間的匹配次數(shù),possessive match
(...) 捕獲括號(hào)。匹配圓括號(hào)子表達(dá)式的輸入范圍在匹配后可用
(?:...) 非捕獲括號(hào)。對包含的模式進(jìn)行分組,但不提供匹配文本的捕獲。比捕捉括號(hào)更有效率。
(?>...) 原子匹配括號(hào)。括號(hào)子表達(dá)式的第一個(gè)匹配是唯一一個(gè)嘗試; 如果它不會(huì)導(dǎo)致整體模式匹配,請?jiān)凇?(?>” 之前的位置備份搜索匹配
(?# ... ) 自由格式的評論(?# comment )。
(?= ... ) 先行斷言 如果括號(hào)內(nèi)的圖案在當(dāng)前輸入位置匹配,但不會(huì)提前輸入位置,則為真。
(?! ... ) 負(fù)面的預(yù)言斷言。如果括號(hào)中的圖案在當(dāng)前輸入位置不匹配,則為真。不提高輸入位置。
(?<= ... ) 瞻性斷言 如果括號(hào)中的模式與當(dāng)前輸入位置之前的文本匹配,則匹配的最后一個(gè)字符就是當(dāng)前位置之前的輸入字符。不改變輸入位置。由look-behind模式匹配的可能字符串的長度不能是無限制的(否*或+運(yùn)算符。
(?<! ... ) 負(fù)面看法斷言。如果括號(hào)中的模式與當(dāng)前輸入位置之前的文本不匹配,則匹配的最后一個(gè)字符就是當(dāng)前位置之前的輸入字符。不改變輸入位置。由look-behind模式匹配的可能字符串的長度不能是無限制的(否*或+運(yùn)算符。)
(?ismwx-ismwx: ... ) 標(biāo)志設(shè)置。使用指定的啟用或禁用的標(biāo)志來評估括號(hào)中的表達(dá)式。標(biāo)志在標(biāo)志選項(xiàng)中定義。
(?ismwx-ismwx) 標(biāo)志設(shè)置。更改標(biāo)志設(shè)置。更改適用于設(shè)置后的模式部分。例如,(?i)更改為不區(qū)分大小寫的匹配。標(biāo)志在標(biāo)志選項(xiàng)中定義。

模板匹配格式

本類提供了使用模板匹配的技術(shù)既可變和不可變的字符串查找和替換的方法。表3描述了語法。

表3模板匹配格式
字符 描述
$n 捕獲組n的文本將被替換為$ n。n必須>= 0和不大于捕獲組的數(shù)量。一個(gè)$沒有后面的數(shù)字沒有什么特別的意義,并且會(huì)以替代文本的形式出現(xiàn)在自己身上$。
將以下字符視為文字,抑制任何特殊含義。替換文本中的反斜杠轉(zhuǎn)義只適用于'$'和'',但可以用于任何其他字符而不會(huì)產(chǎn)生不良影響。

替換字符串被視為模板,$0被匹配范圍$1的內(nèi)容,第一個(gè)捕獲組的內(nèi)容替換,等等。除了表示捕獲組數(shù)量所需的最大值之外的其他數(shù)字將被視為普通字符,$不會(huì)跟隨數(shù)字。反斜杠將難逃都$和\

標(biāo)記選項(xiàng)

以下標(biāo)志控制正則表達(dá)式匹配的各個(gè)方面。
可以使用(?ismx-ismx)模式選項(xiàng)在模式中指定這些標(biāo)志值。當(dāng)使用選項(xiàng)標(biāo)志初始化時(shí),可以為整個(gè)模式指定等效的行為。
NSRegularExpressionNSRegularExpressionOptions

表4 標(biāo)記選項(xiàng)
flag(pattern) 描述
i 如果設(shè)置,匹配將以不區(qū)分大小寫的方式進(jìn)行。
X 如果設(shè)置,允許在模式中使用空格和#comments
s 如果設(shè)置,.模式中的“ ”將匹配輸入文本中的行終止符。默認(rèn)情況下,它不會(huì)。請注意,carriage-return / line-feed pair文本中的內(nèi)容表現(xiàn)為單行終止符,并將匹配.正則表達(dá)式模式中的單個(gè)“ ”
m 以模式控制“ ^”和“ $” 的行為。默認(rèn)情況下,這些僅分別匹配輸入文本的開始和結(jié)束。如果設(shè)置了這個(gè)標(biāo)志,“ ^”和“ $”也將在輸入文本的每一行的開頭和結(jié)尾相匹配。
w 控制模式中的行為\b。如果設(shè)置,則根據(jù)Unicode UAX 29“文本邊界”中發(fā)現(xiàn)的詞的定義找到字邊界。默認(rèn)情況下,通過將字符簡單地分類為“單詞”或“非單詞”來識(shí)別字邊界,其近似于傳統(tǒng)的正則表達(dá)行為。使用兩個(gè)選項(xiàng)獲得的結(jié)果在空格和其他非字符字符的運(yùn)行中可能會(huì)有很大差異。

性能

NSRegularExpression
實(shí)現(xiàn)了非確定性有限自動(dòng)機(jī)匹配引擎。因此,當(dāng)嘗試執(zhí)行匹配時(shí),包含多個(gè)*或+運(yùn)算符的復(fù)雜正則表達(dá)式模式可能會(huì)導(dǎo)致較差的性能 -特別是無法匹配給定的輸入。有關(guān)更多信息,請參閱“ICU用戶指南”“性能提示”部分。

四、OC中的Regular表達(dá)式NSRegularExpression

NSRegularExpression被設(shè)計(jì)為不可變的和線程安全的,因此可以一次使用單個(gè)實(shí)例來匹配多個(gè)線程上的操作。但是,在匹配操作的過程中,無論是從另一個(gè)線程還是在迭代中使用的塊內(nèi),不應(yīng)該在其上操作它的字符串。

1、創(chuàng)建正在表達(dá)式
2、獲取正則表達(dá)式和選項(xiàng)
  • pattern
    返回正則表達(dá)式模式。

  • options
    返回創(chuàng)建正則表達(dá)式選項(xiàng)時(shí)使用的選項(xiàng)。

  • numberOfCaptureGroups
    返回正則表達(dá)式中捕獲組的數(shù)量。

3、使用正則表達(dá)式搜索字符串

- firstMatchInString:options:range:
返回字符串指定范圍內(nèi)正則表達(dá)式的第一個(gè)匹配項(xiàng)。

4、使用正則表達(dá)式替換字符串
5、在字符串中轉(zhuǎn)義
  • + escapedTemplateForString:
    通過根據(jù)需要添加反斜杠轉(zhuǎn)義來返回模板字符串,以保護(hù)符合模式元字符的任何字符

  • + escapedPatternForString:
    通過根據(jù)需要添加反斜杠轉(zhuǎn)義來返回字符串,以保護(hù)符合模式元字符的任何字符。

6、自定義替換功能
7、常數(shù)

五、optionals

1、NSMatching 選項(xiàng)

匹配選項(xiàng)常量指定表達(dá)式匹配方法的報(bào)告,完成和匹配規(guī)則。所有使用正則表達(dá)式搜索或替換值的方法都使用這些常量。

2、NSRegular表達(dá)式選項(xiàng)

五、正則表達(dá)式的使用

1、謂詞(NSPredicate)創(chuàng)建正則表達(dá)式

使用它來判斷用戶輸入的字符串是否為合法的:

// 編寫正則表達(dá)式:只能是數(shù)字或英文,或兩者都存在
NSString *regex = @"^[a-z0-9A-Z]*$";
// 創(chuàng)建謂詞對象并設(shè)定條件的表達(dá)式
NSPredicate *predicate = [NSPredicate predicateWithFormat:@"SELF MATCHES %@", regex];
// 判斷的字符串
NSString *str = @"Hello100";
// 對字符串進(jìn)行判斷
if ([predicate evaluateWithObject:str]) {
    NSLog(@"Match");
}
2、NSString實(shí)例方法

使用rangeOfString:options:方法可以做到,具體看例子:

NSString *phoneNo = @"13143503442";
NSRange range = [phoneNo rangeOfString:@"^1[3]\\d{9}$" options:NSRegularExpressionSearch];
if (range.location != NSNotFound) {
    NSLog(@"%@", [phoneNo substringWithRange:range]);
}

rangeOfString:options:會(huì)返回一個(gè)NSRange,用來接收匹配的范圍,當(dāng)匹配不到結(jié)果時(shí),將會(huì)返回一個(gè)NSIntegerMax最大值,也就是NSNotFound,因此我們可以用它來判斷用戶輸入的內(nèi)容是否符合規(guī)則。

3、NSRegularExpression類創(chuàng)建正則表達(dá)式

我們可以使用正則來過濾并獲取我們想要的特定部分,實(shí)現(xiàn)方法也很簡單,可以用到NSRegularExpression這個(gè)類實(shí)現(xiàn):

NSString *url = @"1229436624@qq.com";
NSError *error;
// 創(chuàng)建NSRegularExpression對象并指定正則表達(dá)式
NSRegularExpression *regex = [NSRegularExpression
                              regularExpressionWithPattern:@"[^@]*\\."
                              options:0
                              error:&error];
if (!error) { // 如果沒有錯(cuò)誤
    // 獲取特特定字符串的范圍
    NSTextCheckingResult *match = [regex firstMatchInString:url
                                                    options:0
                                                      range:NSMakeRange(0, [url length])];
    if (match) {
        // 截獲特定的字符串
        NSString *result = [url substringWithRange:match.range];
        NSLog(@"%@",result);
    }
} else { // 如果有錯(cuò)誤,則把錯(cuò)誤打印出來
    NSLog(@"error - %@", error);
}

這個(gè)例子是從字符串里檢索出以“@”開頭“.”結(jié)尾的區(qū)間字符串,最后檢索出來的字符串結(jié)尾包括“.”,因此此例子最終輸出結(jié)果為“qq.”

4、NSRegularExpression類之抓取多個(gè)結(jié)果

當(dāng)一個(gè)字符串有多個(gè)符合特定規(guī)則的字符,我們可以分別獲取到符合特定規(guī)則的字符:

NSString *regex = @"\\-\\d*\\.";
NSString *str = @"-34023242.-34203020.";
NSError *error;
NSRegularExpression *regular = [NSRegularExpression regularExpressionWithPattern:regex
                                                                         options:NSRegularExpressionCaseInsensitive
                                                                           error:&error];
// 對str字符串進(jìn)行匹配
NSArray *matches = [regular matchesInString:str
                                    options:0
                                      range:NSMakeRange(0, str.length)];
// 遍歷匹配后的每一條記錄
for (NSTextCheckingResult *match in matches) {
    NSRange range = [match range];
    NSString *mStr = [str substringWithRange:range];
    NSLog(@"%@", mStr);
}

從指定字符串中獲取以“-”開頭以“.”結(jié)尾的字符,因?yàn)榭赡苡卸鄠€(gè)符合特定規(guī)則的字符串,因此我們需要把它們遍歷出來,具體輸出結(jié)果如下

017-05-02 16:38:52.309 Juny_regularDemo[1669:190937] -34023242.
2017-05-02 16:38:52.310 Juny_regularDemo[1669:190937] -34203020.

總結(jié):一般來說,判斷用戶輸入的是否合法,只需要方法一就可以了。如果是需要捕獲用戶輸入的特定內(nèi)容,可以用方法二或者方法三、四,如果可能有多個(gè)捕獲結(jié)果,那么可以使用方法四,否則使用方法二。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

推薦閱讀更多精彩內(nèi)容