1. 程式人生 > IOS開發 >iOS深思篇 | 正則表示式

iOS深思篇 | 正則表示式

一. 背景

1.1 簡介

關於正則表示式,相信大家並不陌生,可能平時只是貼上下相關程式碼,並不瞭解裡面所寫匹配規則。這篇文章我們將介紹iOS相關正則表示式基本語法和一些例項,希望看完此文大家能有所收穫;

1.2 工具

線上匹配工具

安裝包

圖形化展示工具

eg:

regulex例項展示圖

二. 認識正則表示式

2.1 概念

正則表示式(又稱規則表示式),英語為Regular Expression

,常簡寫為regexregexpRE。它使用單個字串來描述,匹配一系列符合某個句法規則的字串。

使用場景:

  • 用來批量提取或替換有規律的字串;
  • 在高階文字編輯器中使用;
  • 在各類辦公軟體(office等)中使用;
  • 檢測使用者的輸入是否合法;
  • 在各種開發語言中使用;(C#,java,JS,PHP等)
  • 網路爬蟲;
  • 批量文字處理等;

eg:

Xcode使用場景

2.2 初識篇

正則表示式是由普通字元和特殊字元(也叫元字元或限定符)組成的文字模板,為用來描述或匹配符合某個句法規則的字串。在許多軟體中都得到廣泛的應用,當然針對不同的命令及環境,對正則表示式的支援程度也不盡相同,這裡參考正則表示式 - 應用領域

。有一個通識問題說明一下:

"/"是JS中經常用來分隔一個正則的開始與結尾的字元,其他語言中不用做此區分;

比如:

/* JS */
 /abc/           //精確匹配abc(有/符號)

/* 其他語言 */
  abc            //精確匹配abc(無/符號)
複製程式碼

很多人剛開始無從下手可能是因為不清楚如何"斷句",這樣也就抓不住重點,感覺像聽天書了。?我們可以這樣拆開來看,把正則表示式看成是普通字元和其他字元的集合。普通字元包括所有大寫和小寫字母、所有數字、所有標點符號和一些其他符號(PS:就是平時看得懂的符號?);其他字元包括了常說的元字元、運算子、限定符、特殊字元等等;

下面是一個匹配以數字開頭,並以 abc 結尾的字串;

  ^    [0-9]    +      abc     $


定位符  字符集  限定符  普通字元  限定符
複製程式碼

各種字元的詳細解釋可參照正則表示式 - 語法。之後稍微瞭解一點語法,就可以嘗試自己斷句了,為了少走彎路,建議參照圖形化展示工具regulex對比理解。

2.3 語法篇

語法篇主要參照learn-regex的劃分;大家可以參照作者的線上練習進行學習,下面?僅附上主要元字元對照表。

2.3.1 元字元

正則表示式主要依賴於元字元. 元字元不代表他們本身的字面意思,他們都有特殊的含義. 一些元字元寫在方括號中的時候有一些特殊的意思. 以下是一些元字元的介紹:

元字元 描述
. 句號匹配任意單個字元除了換行符.
[ ] 字元種類. 匹配方括號內的任意字元.
[^ ] 否定的字元種類. 匹配除了方括號裡的任意字元
* 匹配>=0個重複的在*號之前的字元.
+ 匹配>=1個重複的+號前的字元.
? 標記?之前的字元為可選.
{n,m} 匹配num個大括號之前的字元 (n <= num <= m).
(xyz) 字符集,匹配與 xyz 完全相等的字串.
| 或運算子,匹配符號前或後的字元.
\ 轉義字元,用於匹配一些保留的字元 [ ] ( ) { } . * + ? ^ $ \ |
^ 從開始行開始匹配.
$ 從末端開始匹配.
2.3.2 簡寫字符集

正則表示式提供一些常用的字符集簡寫. 如下:

簡寫 描述
. 除換行符外的所有字元
\w 匹配所有字母數字,等同於 [a-zA-Z0-9_]
\W 匹配所有非字母數字,即符號,等同於: [^\w]
\d 匹配數字: [0-9]
\D 匹配非數字: [^\d]
\s 匹配所有空格字元,等同於: [\t\n\f\r\p{Z}]
\S 匹配所有非空格字元: [^\s]
\f 匹配一個換頁符
\n 匹配一個換行符
\r 匹配一個回車符
\t 匹配一個製表符
\v 匹配一個垂直製表符
\p 匹配 CR/LF (等同於 \r\n),用來匹配 DOS 行終止符
2.3.3 零寬度斷言(前後預查)

先行斷言和後發斷言都屬於非捕獲簇(不捕獲文字 ,也不針對組合計進行計數). 先行斷言用於判斷所匹配的格式是否在另一個確定的格式之前,匹配結果不包含該確定格式(僅作為約束).

例如,我們想要獲得所有跟在 $ 符號後的數字,我們可以使用正後發斷言 (?<=\$)[0-9\.]*. 這個表示式匹配 $ 開頭,之後跟著 0,1,2,3,4,5,6,7,8,9,. 這些字元可以出現大於等於 0 次.

零寬度斷言如下:

符號 描述
?= 正先行斷言-存在
?! 負先行斷言-排除
?<= 正後發斷言-存在
?<! 負後發斷言-排除
2.3.4 標誌

標誌也叫模式修正符,因為它可以用來修改表示式的搜尋結果. 這些標誌可以任意的組合使用,它也是整個正則表示式的一部分.

標誌 描述
i 忽略大小寫.
g 全域性搜尋.
m 多行的: 錨點元字元 ^ $ 工作範圍在每行的起始.
2.3.5 優先順序

在這些運算子同時出現時,按照下面的優先順序進行操作。

優先順序 符號
最高 \
( )、(?: )、(?= )、[ ]
*、+、?、{n}、{n,}、{n,m}
^、$、中介字元
最低 |

2.4 進階篇

2.4.1 貪婪匹配與惰性匹配

正則表示式預設採用貪婪匹配模式,在該模式下意味著會匹配儘可能長的子串。我們可以使用 ? 將貪婪匹配模式轉化為惰性匹配模式。 貪婪模式

(.*nt) => People want to try something different.

惰性模式

(.*?nt) => People want to try something different.

常見的惰性限定符:

符號 說明
*? 重複任意次,但儘可能少重複
+? 重複1次或更多次,但儘可能少重複
?? 重複0次或1次,但儘可能少重複
{n,m}? 重複n到m次,但儘可能少重複
{n,}? 重複n次以上,但儘可能少重複

三. iOS中的應用

3.1 謂詞(NSPredicate)

    NSString *regex = @"^[0-9]+$";
    NSPredicate *predicate = [NSPredicate predicateWithFormat:@"SELF MATCHES %@",regex];
    NSString *str = @"1314";
    if ([predicate evaluateWithObject:str]) {
        NSLog(@"Condition Matched");
    }
複製程式碼

3.2 NSString

    NSString *searchText = @"targetString";
    NSRange range = [searchText rangeOfString:@"^[0-9]+$" options:NSRegularExpressionSearch];
    if (range.location != NSNotFound) {
        NSLog(@"target range :%@",[searchText substringWithRange:range]);
    }
複製程式碼

3.3 NSRegularExpression

 /*
typedef NS_OPTIONS(NSUInteger,NSRegularExpressionOptions) {
   NSRegularExpressionCaseInsensitive             = 1 << 0,//不區分字母大小寫的模式
   NSRegularExpressionAllowCommentsAndWhitespace  = 1 << 1,//忽略掉正則表示式中的空格和#號之後的字元
   NSRegularExpressionIgnoreMetacharacters        = 1 << 2,//將正則表示式整體作為字串處理
   NSRegularExpressionDotMatchesLineSeparators    = 1 << 3,//允許.匹配任何字元,包括換行符
   NSRegularExpressionAnchorsMatchLines           = 1 << 4,//允許^和$符號匹配行的開頭和結尾
   NSRegularExpressionUseUnixLineSeparators       = 1 << 5,//設定\n為唯一的行分隔符,否則所有的都有效。
   NSRegularExpressionUseUnicodeWordBoundaries    = 1 << 6 //使用Unicode TR#29標準作為詞的邊界,否則所有傳統正則表示式的詞邊界都有效
};
*/
      NSString *searchText = @"what do you want to match string";
    NSError *error = NULL;
    NSRegularExpression *regex = [NSRegularExpression regularExpressionWithPattern:@"^[0-9]+$" options:NSRegularExpressionCaseInsensitive error:&error];

    //僅取出第一條匹配記錄
    NSTextCheckingResult *firstResult = [regex firstMatchInString:searchText options:0 range:NSMakeRange(0,[searchText length])];
    if (firstResult) {
        NSLog(@"firstResult:%@",[searchText substringWithRange:firstResult.range]);
    }

    //遍歷所有匹配記錄
    NSArray *matches = [regex matchesInString:searchText
                                        options:0
                                          range:NSMakeRange(0,searchText.length)];
    for (NSTextCheckingResult *match in matches) {
        NSRange range = [match range];
        NSString *mStr = [searchText substringWithRange:range];
        NSLog(@"AllResult:%@",mStr);
    }
複製程式碼

學習:

blog

book

video

系列文章: