NSHipster: NSRegular?Expression 中文版

NSHipster

原文: NSRegular?Expression

原作者:Nate Cook


遇到問題磅摹,哦,要用NSRegular?Expression了稠腊。?

其實(shí)呢,有一些淮逻,是要注意的。

正則表達(dá)式是一種DSL, 有一些討論。說他不好,畢竟Regex里面都是各種符號。說他好笆檀,Regex簡明強(qiáng)大,用途廣泛盒至。

公認(rèn)的是酗洒,Cocoa 給NSRegular?Expression 設(shè)計(jì)了一套冗長的API. 先比對下Ruby,這段Ruby代碼的作用是,從HTML代碼片段中提取URL.

htmlSource = "Questions? Corrections? <a href=\"https://twitter.com/NSHipster\"> @NSHipster</a> or <a href=\"https://github.com/NSHipster/articles\">on GitHub</a>."

linkRegex = /<a\s+[^>]*href="([^"]*)"[^>]*>/i

links = htmlSource.scan(linkRegex)

puts(links)

# https://twitter.com/NSHipste

#?https://github.com/NSHipster/articles

Ruby 三行代碼實(shí)現(xiàn)枷遂。

現(xiàn)在看Swift 中用?NSRegularExpression 樱衷,同樣的功能實(shí)現(xiàn)(從HTML代碼片段中提取URL.)

let htmlSource = "Questions? Corrections? <a href=\"https://twitter.com/NSHipster\">?@NSHipster</a> or

<a href=\"https://github.com/NSHipster/articles\">on GitHub</a>."

let linkRegexPattern = "<a\\s+[^>]*href=\"([^\"]*)\"[^>]*>"? ?// 比起Ruby 的, 多了一個(gè)轉(zhuǎn)義字符 '\'

let linkRegex = try! NSRegularExpression(pattern: linkRegexPattern, options: .caseInsensitive )

let matches = linkRegex.matches(in: htmlSource,? range: NSRange(location: 0, length: htmlSource.utf16.count))

let links = matches.map{ result -> String in

? ? ? ?let hrefRange = result.rangeAt(1)

? ? ? ?let start = String.UTF16Index(encodedOffset: hrefRange.location)? ? ? ? ?

? ? ? ?let end = String.UTF16Index(encodedOffset: hrefRange.location + hrefRange.length)

? ? ? return String(htmlSource.utf16[start..<end])!

}

print(links)

// ["https://twitter.com/NSHipster", "https://github.com/NSHipster/articles"]

{

效果圖:?

簡單說明:?

第一段酒唉,? ?<a\\s+ , 先找??<a 兩個(gè)特定字符矩桂, 再來一個(gè)轉(zhuǎn)義,尋找一到多個(gè)空格痪伦。

第二段侄榴, [^>]*, 要求 緊接著的任意的字符串中,不能包含 > .

第三段网沾, href=\" . 尋找緊接著 href=\"?

第四段癞蚕, ([^\"]*),緊接著的任意字符串不得包含?\"

第五段, \"[^>]*> , 先來一個(gè) 轉(zhuǎn)義辉哥,再要求緊接著的字符串滿足 桦山,* 和 > 之間, 不包含 > .

}


NSRegular?Expression 不好的醋旦,就說到這里恒水。

原文(英文原版)不會深入淺出地講解正則表達(dá)式(要自己學(xué)習(xí) 通配符‘*’ ‘+’? , 反向引用‘^’ 饲齐,提前量‘[]’? 钉凌,等等?)

Swift 中的 Regex 學(xué)習(xí),? NSRegularExpression,?NSTextCheckingResult , 注意下難點(diǎn)捂人、特例御雕, 就可以了。

字符串方法 先慷,?NSString?Methods

上手Cocoa中的正則,當(dāng)然是不用?NSRegular?Expression .

NSString 中的?range(of:...) 方法 可實(shí)現(xiàn)輕量級的字符串查找咨察,需要用?.regularExpression 切換 regular expression mode .? ( OC 的 NSString论熙, 對應(yīng) Swift 中的 String)?

OC 代碼

NSString * source = @"For NSSet and NSDictionary, the breaking...";

// 作用是 , 匹配字符串中長得像Cocoa 類型 type 的 單詞

// 例如: UIButton, NSCharacterSet, NSURLSession

NSString * typePattern = @"[A-Z]{3,}[A-Za-z0-9]+";

NSRange typeRange = [source rangeOfString: typePattern options: NSRegularExpressionSearch];

if( typeRange.location! = NSNotFound ){

? ? ? ?NSLog(@"First type: %@",[sourcesubstringWithRange:typeRange]);

? ? ? ?// First type: NSSet

}

Swift 代碼

let source="For NSSet and NSDictionary, the breaking..."

// Matches anything that looks like a Cocoa type:?

// UIButton, NSCharacterSet, NSURLSession, etc.

let typePattern = "[A-Z]{3,}[A-Za-z0-9]+"

if let typeRange = source.range(of: typePattern , options: .regularExpression){

????????print("First type: \(source[typeRange])")

????????// First type: NSSet

}

{


link:?https://regex101.com/r/U7TC8v/1

第一段摄狱, [A-Z]{3,} ,? 用于匹配至少3個(gè)A-Z 中的字符脓诡。

第二段无午, [A-Za-z0-9]+ ,? ?用于匹配至少一個(gè)該集合中的字符,A-Z 之間 加上 a-z 之間祝谚, 再加上 0-9 之間

}

替換也是常用的功能宪迟,同樣的選項(xiàng)option, 使用?replacingOccurrences(of:with:...) .

下面,用一個(gè)看起來怪的代碼交惯,在上句中的coco 類型單詞外面加括號次泽。看起來清楚一些吧席爽。

OC 代碼

NSString * markedUpSource = [source stringByReplacingOccurrencesOfString:typePattern withString: @"`$0`" options: NSRegularExpressionSearch range : NSMakeRange(0,source.length)];

NSLog(@"%@",markedUpSource);

// "For `NSSet` and `NSDictionary`, the breaking..."

Swift 代碼

let markedUpSource = source.replacingOccurrences(of: typePattern, with: "`$0`", options: .regularExpression)

print(markedUpSource)

// "For `NSSet` and `NSDictionary`, the breaking...""

{

說明:?

這里有一個(gè) 正則表達(dá)式中意荤,獲取正則分段的概念。

可以參見 這個(gè)鏈接:?????https://stackoverflow.com/questions/432493/how-do-you-access-the-matched-groups-in-a-javascript-regular-expression

}

用上面的替換模版只锻,正則可以處理推導(dǎo)分組玖像。西方有一個(gè)關(guān)于元音的字母轉(zhuǎn)換,

OC 代碼

NSString * ourcesay = [source stringByReplacingOccurrencesOfString: @"([bcdfghjklmnpqrstvwxyz]*)([a-z]+)" withString: @"$2$1ay" options: NSRegularExpressionSearch | NSCaseInsensitiveSearch range: NSMakeRange(0,source.length)];

NSLog(@"%@",ourcesay);

// "orFay etNSSay anday ictionaryNSDay, ethay eakingbray..."

Swift 代碼

let ourcesay = source.replacingOccurrences(of: "([bcdfghjklmnpqrstvwxyz]*)([a-z]+)", with: "$2$1ay", options: [.regularExpression,.caseInsensitive])

print(ourcesay)

// "orFay etNSSay anday ictionaryNSDay, ethay eakingbray..."

{


link :? ?https://regex101.com/r/lZxWuY/2

第一段齐饮, ([bcdfghjklmnpqrstvwxyz]*)? , 匹配不限長度的 不含 a e i o u 的 任意英文字母捐寥。

第二段,?([a-z]+) ,? 匹配 至少一個(gè)長度的 任意英文字母

}

很多需要運(yùn)用正則的場景下祖驱,上面兩個(gè)方法就可以了握恳。復(fù)雜的功能實(shí)現(xiàn),就要用到NSRegularExpression這個(gè)類了羹膳。首先睡互, 解決Swift中的一個(gè)正則新手易犯錯(cuò)誤。

NSRangeand Swift

比起 Foundation 的 NSString , Swift有著作用域更大陵像、更復(fù)雜的API 就珠,來處理字符串的字符和子串。Swift的標(biāo)準(zhǔn)庫有四種接口來處理字符數(shù)據(jù)醒颖,可以用字符妻怎、Unicode 標(biāo)量、UTF-8 碼泞歉、?UTF-16 碼 來獲取字符串的數(shù)據(jù)逼侦。

這與 NSRegularExpression 相關(guān),很多?NSRegularExpression 方法使用?NSRange腰耙, 用?NSTextCheckingResult 對象保存匹配到的數(shù)據(jù)榛丢。 NSRange 使用整型 integer ,記錄他的起始點(diǎn) location 和 字符長度?length 挺庞。但是字符串 String 是不用整型?integer 作為索引的

let range = NSRange(location: 4, length: 5)

// 下面的代碼晰赞,是編不過的

source[range]

source.characters[range]

source.substring(with:range)

source.substring(with:range.toRange()!)

接著來。

Swift 中的 String 其實(shí)是通過 utf16 接口操作的,同 Foundation 框架下 NSString 的 API 一樣掖鱼∪蛔撸可以通過 utf16 接口的方法,用整型 integer 創(chuàng)建索引戏挡。?

let start = String.UTF16Index(encodedOffset: range.location)

let end = String.UTF16Index(encodedOffset: range.location + range.length)

let substring = String(source.utf16[start..<end])!

// substring 現(xiàn)在是 "NSSet"

下面放一些 String 的 Util 代碼芍瑞,調(diào)用 Swift 相關(guān)正則的語法糖, 有 Objective-C 的感覺

extensionString{

????????/// 這個(gè) nsrange 屬性 褐墅,包含了字符串的所有范圍

????????var nsrange: NSRange{

????????????????return NSRange(location:0,length:utf16.count)

????????}

????????/// 用之前給出的?nsrange 屬性拆檬,返回一個(gè)字串。?

? ? ? ?/// 如果字符串中沒有這個(gè)范圍掌栅, 就 nil 了

????????func substring( with nsrange: NSRange) -> String?{

????????????????guard let range = Range(nsrange, in: self)

????????????????????else { return nil }

? ? ? ? ? ? ? ? ?return String( self[range] )

????????}

????????/// 返回 與之前掏出來的 nsrange 屬性秩仆,等同的 range

????????///?如果字符串中沒有這個(gè)范圍, 就 nil 了

????????func range(from nsrange: NSRange) -> Range<Index>?{

? ??????????????guard let range = Range(nsrange, in: self)? ? ? ? ? ?

? ? ? ? ? ? ? ? ? ? ? ? else { return nil }? ? ? ?

? ? ? ? ? ? ? return range

? ? ? ? ? ? }

? ? ? }

接下來體驗(yàn)的 NSRegularExpression 猾封,有用到上面的 Util 方法澄耍。

NSRegularExpression?和 NSTextCheckingResult

之前學(xué)習(xí)了在字符串中找出第一個(gè)匹配到的數(shù)據(jù),與匹配到的數(shù)據(jù)之間的替換晌缘。復(fù)雜些的情況齐莲,就要用到 NSRegularExpression 了。先造一個(gè)簡單的文本各式匹配 miniPattern 磷箕,找出文本中的 *bold* 和 _italic_

造一個(gè)?NSRegularExpression 對象选酗,要傳入一個(gè)匹配規(guī)則的字符串 pattern ,還有一些選項(xiàng)可以設(shè)置岳枷。miniPattern 用星號?* 或 下劃線?_ 開始查找匹配的單詞芒填。找到星號或下劃線后,就匹配一個(gè)到多個(gè)字符的格式空繁,用找到的第一個(gè)匹配的字符再次match終止一次查找殿衰。匹配到的首字母和文本,都會被保存到查詢結(jié)果中盛泡。

OC 代碼

NSString * miniPattern = @"([*_])(.+?)\\1";

NSError * error = nil;

NSRegularExpression * miniFormatter = [ NSRegularExpression regularExpressionWithPattern: miniPattern options: NSRegularExpressionDotMatchesLineSeparators error: &error];

Swift 代碼

let miniPattern = "([*_])(.+?)\\1"

let miniFormatter = try! NSRegularExpression(pattern: miniPattern, options: .dotMatchesLineSeparators)

// 如果 miniPattern?有誤闷祥, NSRegularExpression 初始化就會拋異常。

如果 pattern有誤傲诵,?NSRegularExpression 初始化就會拋異常凯砍。一旦 NSRegularExpression 對象建好了,就可以用它處理不同的字符串拴竹。

{

說明:?

"([*_])(.+?)\\1"? 悟衩,?這個(gè)正則表達(dá)式? 分三段,

第一段?([*_]) 栓拜,匹配 中括號 中的 任意一個(gè)字符座泳, 就是 * 或者 _ ;

第二段?(.+?) 斑响, 匹配 長度大于1的 任意字符串;

第三段?\\1钳榨, 有一個(gè)轉(zhuǎn)義字符, 匹配之前獲取到的第一個(gè)同等字符串

}

OC 代碼

NSString * text = @"MiniFormatter handles *bold* and _italic_ text.";

NSArray?* matches = [miniFormatter matchesInString: text options: kNilOptions range:? NSMakeRange(0,text.length)];

// matches.count == 2

Swift 代碼

let text = "MiniFormatter handles *bold* and _italic_ text."

let matches = miniFormatter.matches(in: text, options: [], range: text.nsrange )

// matches.count == 2

調(diào)用?matches(in:options:range:) 方法纽门,可以取出包含 NSTextCheckingResult 元素的數(shù)組薛耻。 多種文本處理類都有用到NSTextCheckingResult 類型,譬如?NSDataDetector?和 NSSpellChecker . 返回的數(shù)組中赏陵,一個(gè)匹配有一個(gè)NSTextCheckingResult .

通常要取得的是匹配到的范圍饼齿,就在每個(gè)結(jié)果的range屬性里面。通常要取得的還有蝙搔,正則表達(dá)式中任意匹配到的范圍缕溉。 可以通過?numberOfRanges 屬性 和?rangeAt(_:) 方法,找出指定的范圍吃型。

range(at:)

Returns the result type that the range represents.

range(at:) 方法证鸥, 返回的結(jié)果就是對應(yīng)的范圍

Discussion

A result must have at least one range, but may optionally have more (for example, to represent regular expression capture groups).

Passing?range(at:)?the value?0?always returns the value of the the?range?property. Additional ranges, if any, will have indexes from?1?to?numberOfRanges-1.

討論下,

返回的結(jié)果勤晚,至少有一個(gè)范圍枉层。往往有更多,可選的赐写。( 正則表達(dá)式捕獲組鸟蜡,對應(yīng)的)

?range(at:) 方法返回的第一個(gè)結(jié)果,就是 range 屬性的值挺邀。如果有額外的揉忘,返回的結(jié)果對應(yīng)的索引就是從 1 到?numberOfRanges-1? ?

引用下?蘋果文檔?,

?range 0 是完全匹配到的范圍端铛,也是肯定能取到的泣矛。

然后從第1個(gè)到 第(numberOfRanges - 1)個(gè)的 ranges 數(shù)組中的值,就是分段沦补,對應(yīng)每一段正則匹配的結(jié)果乳蓄。

使用之前給出的NSRange的取子串方法,就可以用 range 來取出匹配到的結(jié)果夕膀。

OC 代碼

for match in matches {

? ? ? ?let stringToFormat = text.substring(with: match.rangeAt(2))!

? ? ? ?switch text.substring(with: match.rangeAt(1))! {?

? ? ? ?case "*" :

? ? ? ? ?????????print("Make bold: '\(stringToFormat)'")

????????case "_" :

????????????????print("Make italic: '\(stringToFormat)'")

????????default :

????????????????break

????????????????}

}

// 打印出

// Make bold: 'bold'

// Make italic: 'italic'

Swift 代碼

for match in matches {

????let stringToFormat = text.substring(with:?match.range(at: 2) )!

????switch text.substring(with:?match.range(at: 1)? )! {

????case "*" :

????????????print("Make bold: '\(stringToFormat)'")

????case "_":

????????????print("Make italic: '\(stringToFormat)'")

????default: break

????}

}

// 打印出

// Make bold: 'bold'

// Make italic: 'italic'

對于基礎(chǔ)的替換虚倒,直接用??stringByReplacingMatches(in:options:range:with:) 方法,?String.replacingOccurences(of:with:options:) 的加強(qiáng)版 产舞。上例中魂奥,不同的正則匹配 (?bold , italic)易猫,用不同的替換模版耻煤。

按照倒敘,循環(huán)訪問這些匹配結(jié)果,這樣就不會把后面的 match 范圍搞亂哈蝇。

var formattedText = text

Format:?

for match inmatches.reversed () {

????let template: String

????switch text.substring(with:?match.range(at:1)? ) ?? ""{

????case "*":

?????????template? = "<strong>$2</strong>"

????case "_":?

????????template = "<em>$2</em>"????

????default:????break Format

????}

????let matchRange = formattedText.range(from:match.range)! ????????// see above?

????let replacement = miniFormatter.replacementString( for: match, in: formattedText, offset: 0, template: template)

????formattedText.replaceSubrange( matchRange , with: replacement)

}

// 'formattedText' is now:

// "MiniFormatter handles bold and italic text."

通過自定義的模版棺妓,調(diào)用?miniFormatter.replacementString(for:in:...) 方法, 然后呢炮赦,每一個(gè)NSTextCheckingResult 實(shí)例會隨之產(chǎn)生一個(gè)對應(yīng)的替換字符串怜跑。

Expression and Matching Options? ?, 表達(dá)式與匹配選項(xiàng)

NSRegularExpression 是高度可配置的吠勘。弄一個(gè)實(shí)例性芬,或者調(diào)用執(zhí)行正則匹配的方法,都可以傳不同選項(xiàng)的組合剧防。

NSRegularExpression.Options

* .caseInsensitive : 字母大小寫忽略植锉。 開啟字母大小寫忽略的匹配,就是 i 標(biāo)記

*?.allowCommentsAndWhitespace : 允許注釋峭拘、空格俊庇。 忽略 # 和句尾間任意的空格和注釋。所以所以你可以嘗試格式化和記錄正則匹配鸡挠,有了注釋和空格暇赤,正則會好讀一點(diǎn)。 等價(jià)于 x 標(biāo)記

*?.ignoreMetacharacters: 忽略元符號宵凌,忽略關(guān)鍵字鞋囊。String.range(of:options:) 方法中的去正則化,與 .regularExpression 正則選項(xiàng)相反瞎惫。這實(shí)際上就是正則變?yōu)楹唵蔚奈谋舅阉髁锔雎运械恼齽t關(guān)鍵字和運(yùn)算符。

*?.dotMatchesLineSeparators: 句點(diǎn)分行匹配瓜喇。允許 , 關(guān)鍵字匹配換行符以及其他字符挺益。就是 s 標(biāo)記。

*?.anchorsMatchLines: 句中錨點(diǎn)匹配乘寒。允許 ^ (開始)和 $ (結(jié)束)關(guān)鍵字望众,匹配句中的開始和結(jié)束。而不僅僅是輸入的整段的開始和結(jié)尾伞辛。就是 m 標(biāo)記

*?.useUnixLineSeparators,?.useUnicodeWordBoundaries:? 最后兩項(xiàng)優(yōu)化了更多特定的行和字的邊界處理烂翰。Unix 行分隔符。

NSRegularExpression.MatchingOptions? ? ?正則表達(dá)式的匹配選項(xiàng)

一個(gè) NSRegularExpression 正則表達(dá)式實(shí)例中蚤氏,可以傳入選項(xiàng)來調(diào)整匹配的方法甘耿。

*?.anchored:? ?錨定的。僅匹配搜索范圍的開頭第一段竿滨。

*?.withTransparentBounds: 超過界限佳恬。允許正則在搜索范圍前捏境,向前查找。反之毁葱,向后查找垫言。還有單詞的邊界。(盡管不適用于倾剿,實(shí)際的匹配字符)

static var?withTransparentBounds: NSRegularExpression.MatchingOptions

Specifies that matching may examine parts of the string beyond the bounds of the search range, for purposes such as word boundary detection, lookahead, etc. This constant has no effect if the search range contains the entire string. See?enumerateMatches(in:options:range:using:)?for a description of the constant in context.

蘋果 鏈接:? https://developer.apple.com/documentation/foundation/nsregularexpression.matchingoptions


* .withoutAnchoringBounds : 無錨定界限骏掀。 讓 ^ 和 $ 關(guān)鍵字僅匹配字符串的開始和結(jié)尾,而不是搜索范圍的開始和結(jié)束柱告。

*?.reportCompletion ( 報(bào)告完成 ) ,?.reportProgress ( 報(bào)告進(jìn)度 ):? 這些參數(shù)選項(xiàng)僅在下節(jié)講的部分匹配方法中有用。當(dāng)正則查找完成了笑陈,或者是耗時(shí)的匹配上有進(jìn)度际度,相應(yīng)選項(xiàng)會通知?NSRegular?Expression 傳入附加時(shí)間,調(diào)用枚舉塊涵妥。

Partial Matching? ? ? ?部分匹配

最后乖菱,?NSRegular?Expression 最強(qiáng)大的特性之一是,僅掃描字符串中需要的部分蓬网。處理長文本窒所,挺有用的。處理耗資源的正則匹配帆锋,也是吵取。

不要用這兩個(gè)方法?firstMatch(in:...) matches(in:...) , 調(diào)用?enumerateMatches(in:options:range:using:) 锯厢,用閉包處理對應(yīng)的匹配皮官。

func? enumerateMatches( instring :?String, options:NSRegularExpression.MatchingOptions= [], range:NSRange,? usingblock:? (NSTextCheckingResult?,NSRegularExpression.MatchingFlags,UnsafeMutablePointer<ObjCBool>) ->Void)

蘋果鏈接:?https://developer.apple.com/documentation/foundation/nsregularexpression/1409687-enumeratematches

這個(gè)閉包接收三個(gè)參數(shù),匹配的正則結(jié)果实辑,一組標(biāo)志選項(xiàng)捺氢, 一個(gè)布爾指針。 這個(gè) bool 指針是一個(gè)只出參數(shù)剪撬,可以通過它在設(shè)定的時(shí)機(jī)停止處理摄乒。

可以用這個(gè)方法在?Dostoevsky 的?Karamazov?兄弟一書中, 查找開始的幾個(gè)名字。名字遵從的規(guī)則是残黑,首名馍佑,中間父姓 ( 例如: “Ivan Fyodorovitch” )

OC 代碼

NSString * namePattern = @"([A-Z]\\S+)\\s+([A-Z]\\S+(vitch|vna))";

NSRegularExpression * nameRegex = [NSRegularExpression regularExpressionWithPattern: namePatternoptions: kNilOptionserror: &error];

NSString * bookString = ...

NSMutableSet * name = [NSMutableSet set ];

[nameRegex enumerateMatchesInString: bookString options: kNilOptions range: NSMakeRange(0 , [ bookString length ] ) usingBlock: ^( NSTextCheckingResult * result , NSMatchingFlags flags , BOOL * stop ){

????if ( result == nil ) return;

????NSString * name = [nameRegex replacementStringForResult : resultinString : bookStringoffset : 0 template: @"$1 $2" ];

????[names addObject: name ];

????// stop once we've found six unique names

????*stop = ( names.count==6);

} ] ;

Swift 代碼

let nameRegex = try! NSRegularExpression( pattern: "([A-Z]\\S+)\\s+([A-Z]\\S+(vitch|vna))" )

let bookString = ...

var names:Set?= []

nameRegex.enumerateMatches( in: bookString, range: bookString.nsrange ){

????( result , _ , stopPointer )? ? ? in

????guard let result = result else { return }

????let name = nameRegex.replacementString( for: result , in:? bookString , offset : 0 , template: "$1 $2" )

????names.insert(name)

????// stop once we've found six unique names ,通過?Set 確保梨水,6個(gè)不一樣的名字文本?

????stopPointer.pointee = ObjCBool( names.count==6 )

}

// names.sorted():

// ["Adela?da Ivanovna", "Alexey Fyodorovitch", "Dmitri Fyodorovitch",

// "Fyodor Pavlovitch", "Pyotr Alexandrovitch", "Sofya Ivanovna"]

通過這種途徑挤茄,我們只需查找前 45 個(gè)匹配,而不是把全書中接近1300個(gè)名字都找一遍冰木。性能顯著提高穷劈。

一旦有所認(rèn)識笼恰,NSRegularExpression 就會超級有用。除了 NSRegularExpression , 還有一個(gè)類?NSDataDetector?.?NSDataDetector?是一個(gè)用于識別有用信息的類歇终,可以用來處理用戶相關(guān)的文本社证,查找日期,地址與手機(jī)號碼评凝。通過Fundation 框架處理文本追葡,NSRegularExpression 強(qiáng)大,健壯奕短,有簡潔的接口宜肉,也有深入




說明: 為了有意思一些, 我采取了意譯翎碑。并加入了一些 Regex 細(xì)節(jié)與擴(kuò)展資料谬返。

文中 出現(xiàn)的 Swift 代碼, 已校正到 Swift 4 .

謝謝觀看

PS: 參考資料

文中的 Swift 代碼日杈,github 地址:?https://github.com/dengV/regex_001

超好用的正則網(wǎng)站:101

熟悉的 ray wenderlich tutorial?: 我升級了對應(yīng)的Swift代碼遣铝,?github 鏈接

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市莉擒,隨后出現(xiàn)的幾起案子酿炸,更是在濱河造成了極大的恐慌,老刑警劉巖涨冀,帶你破解...
    沈念sama閱讀 206,126評論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件填硕,死亡現(xiàn)場離奇詭異,居然都是意外死亡鹿鳖,警方通過查閱死者的電腦和手機(jī)廷支,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,254評論 2 382
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來栓辜,“玉大人恋拍,你說我怎么就攤上這事∨核Γ” “怎么了施敢?”我有些...
    開封第一講書人閱讀 152,445評論 0 341
  • 文/不壞的土叔 我叫張陵,是天一觀的道長狭莱。 經(jīng)常有香客問我僵娃,道長,這世上最難降的妖魔是什么腋妙? 我笑而不...
    開封第一講書人閱讀 55,185評論 1 278
  • 正文 為了忘掉前任默怨,我火速辦了婚禮,結(jié)果婚禮上骤素,老公的妹妹穿的比我還像新娘匙睹。我一直安慰自己愚屁,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 64,178評論 5 371
  • 文/花漫 我一把揭開白布痕檬。 她就那樣靜靜地躺著霎槐,像睡著了一般。 火紅的嫁衣襯著肌膚如雪梦谜。 梳的紋絲不亂的頭發(fā)上丘跌,一...
    開封第一講書人閱讀 48,970評論 1 284
  • 那天,我揣著相機(jī)與錄音唁桩,去河邊找鬼闭树。 笑死,一個(gè)胖子當(dāng)著我的面吹牛荒澡,可吹牛的內(nèi)容都是我干的报辱。 我是一名探鬼主播,決...
    沈念sama閱讀 38,276評論 3 399
  • 文/蒼蘭香墨 我猛地睜開眼仰猖,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了奈籽?” 一聲冷哼從身側(cè)響起饥侵,我...
    開封第一講書人閱讀 36,927評論 0 259
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎衣屏,沒想到半個(gè)月后躏升,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 43,400評論 1 300
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡狼忱,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 35,883評論 2 323
  • 正文 我和宋清朗相戀三年膨疏,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片钻弄。...
    茶點(diǎn)故事閱讀 37,997評論 1 333
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡佃却,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出窘俺,到底是詐尸還是另有隱情饲帅,我是刑警寧澤,帶...
    沈念sama閱讀 33,646評論 4 322
  • 正文 年R本政府宣布瘤泪,位于F島的核電站灶泵,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏对途。R本人自食惡果不足惜赦邻,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,213評論 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望实檀。 院中可真熱鬧惶洲,春花似錦按声、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,204評論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至币呵,卻和暖如春怀愧,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背余赢。 一陣腳步聲響...
    開封第一講書人閱讀 31,423評論 1 260
  • 我被黑心中介騙來泰國打工芯义, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人妻柒。 一個(gè)月前我還...
    沈念sama閱讀 45,423評論 2 352
  • 正文 我出身青樓扛拨,卻偏偏與公主長得像,于是被迫代替她去往敵國和親举塔。 傳聞我的和親對象是個(gè)殘疾皇子绑警,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 42,722評論 2 345

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