Swift:字符串和字符

Swift 的 String 類型與 Foundation NSString 類進行了無縫橋接。Foundation 也可以對 String 進行擴展撵摆,暴露在 NSString 中定義的方法。 這意味著羡亩,如果你在 String 中調用這些 NSString 的方法薇搁,將不用進行轉換。

一谴仙、字符串字面量

  • 可以在代碼中使用預定義的字符串值來作為字符串字面量
let someString = "Some string literal value"

二、多行字符串字面量

  • 如果需要一個字符串是跨行的, 可以使用多行字符串字面量
let quotation = """
The White Rabbit put on his spectacles.  "Where shall I begin,
please your Majesty?" he asked.

"Begin at the beginning," the King said gravely, "and go on
till you come to the end; then stop."
"""
  • 打印結果
image.png
  • 可以使用續(xù)行符(\), 將兩行字符串打印到同一行
let quotation = """
The White Rabbit put on his spectacles.  "Where shall I begin, \
please your Majesty?" he asked.

"Begin at the beginning," the King said gravely, "and go on \
till you come to the end; then stop."
"""
  • 打印結果如下, 只有兩行打印
image.png

三碾盐、字符串字面量的特殊字符

  • 字符串字面量可以包含以下特殊字符
轉義字符:
\0    空字符
\\    反斜杠
\t    水平制表符
\n    換行符
\r    回車符
\"    雙引號
\'    單引號

Unicode標量:
\u{n}    u 小寫, 其中 n 為任意一到八位十六進制數(shù)且可用的Unicode位碼
  • 例子
let wiseWords = "\"Imagination is more important than knowledge\" - Einstein"
// "Imageination is more important than knowledge" - Enistein
let dollarSign = "\u{24}"             // $晃跺,Unicode 標量 U+0024
let blackHeart = "\u{2665}"           // ?,Unicode 標量 U+2665
let sparklingHeart = "\u{1F496}"      // ??毫玖,Unicode 標量 U+1F496
  • 由于多行字符串字面量使用了三個雙引號掀虎,而不是一個,所以你可以在多行字符串字面量里直接使用雙引號(")而不必加上轉義符(\)付枫。要在多行字符串字面量中使用 """ 的話烹玉,就需要使用至少一個轉義符(\):
let threeDoubleQuotes = """
Escaping the first quote \"""
Escaping all three quotes \"\"\"
"""

四、初始化空字符串

  • 創(chuàng)建一個空字符串變量的兩種方法
var one = ""
var two = String()
// 兩個字符串都為空, 并等價
  • 可以通過Bool類型的isEmpty屬性來判斷該字符串是否為空
if one.isEmpty {
    print("字符串為空")
}
// 打印: 字符串為空

五阐滩、字符串可變性

  • 可以通過將一個特定字符串分配給一個變量來對其進行修改, 或者分配給一個常量來保證其不會被修改
var variableString = "Horse"
variableString += " and carriage"
// variableString 現(xiàn)在為 "Horse and carriage"

let constantString = "Highlander"
constantString += " and another Highlander"
// 這會報告一個編譯錯誤(compile-time error) - 常量字符串不可以被修改二打。

六、字符串是值類型

  • Swift的String類型是值類型叶眉。 如果您創(chuàng)建了一個新的字符串址儒,那么當其進行常量、變量賦值操作衅疙,或在函數(shù)/方法中傳遞時莲趣,會進行值拷貝。 任何情況下饱溢,都會對已有字符串值創(chuàng)建新副本喧伞,并對該新副本進行傳遞或賦值操作。

  • Swift 默認字符串拷貝的方式保證了在函數(shù)/方法中傳遞的是字符串的值绩郎。 很明顯無論該值來自于哪里潘鲫,都是您獨自擁有的。 您可以確信傳遞的字符串不會被修改肋杖,除非你自己去修改它溉仑。

七、使用字符

  • 可以通過for-in循環(huán)來便利字符串, 獲取字符串中每一個字符的值
for character in "Dog!??" {
    print(character)
}
  • 通過標明一個 Character 類型并用字符字面量進行賦值状植,可以建立一個獨立的字符常量或變量:
let exclamationMark: Character = "!"
  • 字符串可以通過傳遞一個值類型為 Character 的數(shù)組作為自變量來初始化:
let catCharacters: [Character] = ["C", "a", "t", "!", "??"]
let catString = String(catCharacters)
print(catString)
// 打印輸出:"Cat!??"

八浊竟、連接字符串和字符

  • 字符串可以通過加法運算符(+)相加在一起(或稱“連接”)創(chuàng)建一個新的字符串:
let string1 = "hello"
let string2 = " there"
var welcome = string1 + string2
// welcome 現(xiàn)在等于 "hello there"
  • 也可以通過加法賦值運算符(+=)將一個字符串添加到一個已經存在字符串變量上:
var instruction = "look over"
instruction += string2
// instruction 現(xiàn)在等于 "look over there"
  • 您可以用 append() 方法將一個字符附加到一個字符串變量的尾部:
let exclamationMark: Character = "!"
welcome.append(exclamationMark)
// welcome 現(xiàn)在等于 "hello there!"

注意
您不能將一個字符串或者字符添加到一個已經存在的字符變量上怨喘,因為字符變量只能包含一個字符。

  • 如果你需要使用多行字符串字面量來拼接字符串振定,并且你需要字符串每一行都以換行符結尾必怜,包括最后一行:
let badStart = """
one
two
"""
let end = """
three
"""
print(badStart + end)
// 打印兩行:
// one
// twothree

let goodStart = """
one
two

"""
print(goodStart + end)
// 打印三行:
// one
// two
// three

九、字符串差值

字符串插值是一種構建新字符串的方式后频,可以在其中包含常量梳庆、變量、字面量和表達式卑惜。字符串字面量和多行字符串字面量都可以使用字符串插值膏执。 您插入的字符串字面量的每一項都在以反斜線為前綴的圓括號中:

let multiplier = 3
let message = "\(multiplier) times 2.5 is \(Double(multiplier) * 2.5)"
// message 是 "3 times 2.5 is 7.5"

注意
插值字符串中寫在括號中的表達式不能包含非轉義反斜杠(\),并且不能包含回車或換行符露久。不過胧后,插值字符串可以包含其他字面量

Unicode: 是一個國際標準,用于文本的編碼和表示抱环。 它使您可以用標準格式表示來自任意語言幾乎所有的字符,并能夠對文本文件或網(wǎng)頁這樣的外部資源中的字符進行讀寫操作纸巷。

十镇草、Unicode 標量

  • Swift 的 String 類型是基于 Unicode 標量 建立的。 Unicode 標量是對應字符或者修飾符的唯一的21位數(shù)字瘤旨,例如 U+0061 表示小寫的拉丁字母(LATIN SMALL LETTER A)("a")梯啤,U+1F425 表示小雞表情(FRONT-FACING BABY CHICK)("??")。

注意
Unicode 碼位(code poing) 的范圍是 U+0000 到 U+D7FF 或者 U+E000 到 U+10FFFF存哲。Unicode 標量不包括 Unicode 代理項(surrogate pair) 碼位因宇,其碼位范圍是 U+D800 到 U+DFFF。

  • 注意不是所有的21位 Unicode 標量都代表一個字符祟偷,因為有一些標量是留作未來分配的察滑。已經代表一個典型字符的標量都有自己的名字,例如上面例子中的 LATIN SMALL LETTER AFRONT-FACING BABY CHICK修肠。

十一贺辰、可擴展的字形群集

  • 每一個 Swift 的 Character 類型代表一個可擴展的字形群。

一個可擴展的字形群是一個或多個可生成人類可讀的字符 Unicode 標量的有序排列嵌施。

  • 舉個例子饲化,字母 é 可以用單一的 Unicode 標量 é(LATIN SMALL LETTER E WITH ACUTE, 或者 U+00E9)來表示。

  • 然而一個標準的字母 e(LATIN SMALL LETTER E 或者 U+0065) 加上一個急促重音(COMBINING ACTUE ACCENT)的標量(U+0301)吗伤,這樣一對標量就表示了同樣的字母 é吃靠。 這個急促重音的標量形象的將 e 轉換成了 é

let eAcute: Character = "\u{E9}"                         // é
let combinedEAcute: Character = "\u{65}\u{301}"          // e 后面加上  ?
// eAcute 是 é, combinedEAcute 是 é
  • 可擴展的字符群集是一個靈活的方法足淆,用許多復雜的腳本字符表示單一的 Character 值巢块。 例如礁阁,來自朝鮮語字母表的韓語音節(jié)能表示為組合或分解的有序排列。 在 Swift 都會表示為同一個單一的 Character 值:
let precomposed: Character = "\u{D55C}"                  // ?
let decomposed: Character = "\u{1112}\u{1161}\u{11AB}"   // ?, ?, ?
// precomposed 是 ?, decomposed 是 ?
  • 可拓展的字符群集可以使包圍記號(例如 COMBINING ENCLOSING CIRCLE或者 U+20DD)的標量包圍其他 Unicode 標量夕冲,作為一個單一的 Character 值:
let enclosedEAcute: Character = "\u{E9}\u{20DD}"
// enclosedEAcute 是 é?
  • 地域性指示符號的 Unicode 標量可以組合成一個單一的 Character 值氮兵,例如 REGIONAL INDICATOR SYMBOL LETTER U(U+1F1FA)和 REGIONAL INDICATOR SYMBOL LETTER S(U+1F1F8):
let regionalIndicatorForUS: Character = "\u{1F1FA}\u{1F1F8}"
// regionalIndicatorForUS 是 ????

十二、計算字符數(shù)量

  • 如果想要獲得一個字符串中 Character 值的數(shù)量歹鱼,可以使用 count 屬性:
let unusualMenagerie = "Koala ??, Snail ??, Penguin ??, Dromedary ??"
print("unusualMenagerie has \(unusualMenagerie.count) characters")
// 打印輸出 "unusualMenagerie has 40 characters"
  • 注意在 Swift 中泣栈,使用可拓展的字符群集作為 Character 值來連接或改變字符串時,并不一定會更改字符串的字符數(shù)量弥姻。

  • 例如南片,如果你用四個字符的單詞 cafe 初始化一個新的字符串,然后添加一個 COMBINING ACTUE ACCENT(U+0301)作為字符串的結尾庭敦。最終這個字符串的字符數(shù)量仍然是 4疼进,因為第四個字符是 é,而不是 e

var word = "cafe"
print("the number of characters in \(word) is \(word.count)")
// 打印輸出 "the number of characters in cafe is 4"

word += "\u{301}"    // 拼接一個重音秧廉,U+0301

print("the number of characters in \(word) is \(word.count)")
// 打印輸出 "the number of characters in café is 4"
注意:
可擴展的字符群集可以組成一個或者多個 Unicode 標量伞广。
這意味著不同的字符以及相同字符的不同表示方式可能需要不同數(shù)量的內存空間來存儲。
所以 Swift 中的字符在一個字符串中并不一定占用相同的內存空間數(shù)量疼电。
因此在沒有獲取字符串的可擴展的字符群的范圍時候嚼锄,就不能計算出字符串的字符數(shù)量。
如果您正在處理一個長字符串蔽豺,需要注意 count 屬性必須遍歷全部的 Unicode 標量区丑,來確定字符串的字符數(shù)量。
  • 另外需要注意的是通過 count 屬性返回的字符數(shù)量并不總是與包含相同字符的 NSStringlength 屬性相同修陡。NSStringlength 屬性是利用 UTF-16 表示的十六位代碼單元數(shù)字沧侥,而不是 Unicode 可擴展的字符群集。
let abc = "This is \u{E9}\u{20DD}"
print(abc, abc.count)              // 打印: This is é? 9
let def = abc as NSString
print(def, def.length)             // 打印: This is é? 10

十三魄鸦、訪問和修改字符串

  • 你可以通過字符串的屬性和方法來訪問和修改它宴杀,當然也可以用下標語法完成。
1拾因、字符串索引
  • 每一個String值時都有一個關聯(lián)的索引(index)類型, String.Index, 它對應著字符串中的每一個Character的位置

  • 不同的字符可能會占用不同數(shù)量的內存空間, 所以要知道Character的確定位置, 就必須從String開頭遍歷每一個Unicode標量知道結尾婴氮。因此,Swift 的字符串不能用整數(shù)(integer)做索引盾致。

  • 使用 startIndex 屬性可以獲取一個 String 的第一個 Character 的索引主经。使用 endIndex 屬性可以獲取最后一個 Character 的后一個位置的索引。因此庭惜,endIndex 屬性不能作為一個字符串的有效下標罩驻。如果 String 是空串,startIndexendIndex 是相等的护赊。

let abc = "This is \u{E9}\u{20DD}"
print(abc.startIndex)
print(abc.endIndex)

控制臺打印:
Index(_compoundOffset: 0, _cache: Swift.String.Index._Cache.utf16)
Index(_compoundOffset: 40, _cache: Swift.String.Index._Cache.utf16)
  • 通過調用 Stringindex(before:)index(after:) 方法惠遏,可以立即得到前面或后面的一個索引砾跃。您還可以通過調用 index(_:offsetBy:) 方法來獲取對應偏移量的索引,這種方式可以避免多次調用 index(before:)index(after:) 方法节吮。
let greeting = "Guten Tag!"
greeting[greeting.startIndex]
// G
greeting[greeting.index(before: greeting.endIndex)]
// !
greeting[greeting.index(after: greeting.startIndex)]
// u
let index = greeting.index(greeting.startIndex, offsetBy: 7)
greeting[index]
// a
  • 試圖獲取越界索引對應的 Character抽高,將引發(fā)一個運行時錯誤。
greeting[greeting.endIndex] // error
greeting.index(after: endIndex) // error
  • 使用 indices 屬性會創(chuàng)建一個包含全部索引的范圍(Range)透绩,用來在一個字符串中訪問單個字符翘骂。
for index in greeting.indices {
   print("\(greeting[index]) ", terminator: "")
}
// 打印輸出 "G u t e n   T a g ! "
2、插入和刪除
  • 調用 insert(_:at:) 方法可以在一個字符串的指定索引插入一個字符
var welcome = "hello"
welcome.insert("!", at: welcome.endIndex)
// welcome 變量現(xiàn)在等于 "hello!"
  • 調用 insert(contentsOf:at:) 方法可以在一個字符串的指定索引插入一個段字符串帚豪。
welcome.insert(contentsOf:" there", at: welcome.index(before: welcome.endIndex))
// welcome 變量現(xiàn)在等于 "hello there!"
  • 調用 remove(at:) 方法可以在一個字符串的指定索引刪除一個字符
welcome.remove(at: welcome.index(before: welcome.endIndex))
// welcome 現(xiàn)在等于 "hello there"
  • 調用 removeSubrange(_:) 方法可以在一個字符串的指定索引刪除一個子字符串碳竟。
let range = welcome.index(welcome.endIndex, offsetBy: -6)..<welcome.endIndex
welcome.removeSubrange(range)
// welcome 現(xiàn)在等于 "hello"

十四、子字符串

  • 使用下標或者 prefix(_:) 之類的方法 —— 就可以得到一個 SubString 的實例狸臣,而非另外一個 String

  • Swift 里的 SubString 絕大部分函數(shù)都跟 String 一樣莹桅,意味著你可以使用同樣的方式去操作 SubStringString

  • 然而烛亦,跟 String 不同的是诈泼,你只有在短時間內需要操作字符串時,才會使用 SubString煤禽。當你需要長時間保存結果時厂汗,就把 SubString 轉化為 String 的實例:

let say = "hello, world!"
let index = say.index(of: ",") ?? say.endIndex
let result = say[..<index]
// result 得知為 "hello"

// 把結果轉化為 String 以便長期存儲。
let newString = String(result)

十五呜师、比較字符串

Swift 提供了三種方式來比較文本值:字符串字符相等、前綴相等和后綴相等贾节。

1汁汗、字符串/字符相等
  • 字符串/字符可以用等于操作符(==)和不等于操作符(!=
let quotation = "We're a lot alike, you and I."
let sameQuotation = "We're a lot alike, you and I."
if quotation == sameQuotation {
    print("These two strings are considered equal")
}
// 打印輸出 "These two strings are considered equal"
2、前綴/后綴相等
  • 通過調用字符串的 hasPrefix(_:)/hasSuffix(_:) 方法來檢查字符串是否擁有特定前綴/后綴栗涂,兩個方法均接收一個 String 類型的參數(shù)知牌,并返回一個布爾值。
  • 下面的例子以一個字符串數(shù)組表示莎士比亞話劇《羅密歐與朱麗葉》中前兩場的場景位置:
let romeoAndJuliet = [
    "Act 1 Scene 1: Verona, A public place",
    "Act 1 Scene 2: Capulet's mansion",
    "Act 1 Scene 3: A room in Capulet's mansion",
    "Act 1 Scene 4: A street outside Capulet's mansion",
    "Act 1 Scene 5: The Great Hall in Capulet's mansion",
    "Act 2 Scene 1: Outside Capulet's mansion",
    "Act 2 Scene 2: Capulet's orchard",
    "Act 2 Scene 3: Outside Friar Lawrence's cell",
    "Act 2 Scene 4: A street in Verona",
    "Act 2 Scene 5: Capulet's mansion",
    "Act 2 Scene 6: Friar Lawrence's cell"
]
  • 您可以調用 hasPrefix(_:) 方法來計算話劇中第一幕的場景數(shù):
var act1SceneCount = 0
for scene in romeoAndJuliet {
    if scene.hasPrefix("Act 1 ") {
        act1SceneCount += 1
    }
}
print("There are \(act1SceneCount) scenes in Act 1")
// 打印輸出 "There are 5 scenes in Act 1"
  • 相似地斤程,您可以用 hasSuffix(_:) 方法來計算發(fā)生在不同地方的場景數(shù):
var mansionCount = 0
var cellCount = 0
for scene in romeoAndJuliet {
    if scene.hasSuffix("Capulet's mansion") {
        mansionCount += 1
    } else if scene.hasSuffix("Friar Lawrence's cell") {
        cellCount += 1
    }
}
print("\(mansionCount) mansion scenes; \(cellCount) cell scenes")
// 打印輸出 "6 mansion scenes; 2 cell scenes"

注意
hasPrefix(_:)hasSuffix(_:) 方法都是在每個字符串中逐字符比較其可擴展的字符群集是否標準相等

?著作權歸作者所有,轉載或內容合作請聯(lián)系作者
  • 序言:七十年代末角寸,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子忿墅,更是在濱河造成了極大的恐慌扁藕,老刑警劉巖,帶你破解...
    沈念sama閱讀 219,188評論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件疚脐,死亡現(xiàn)場離奇詭異亿柑,居然都是意外死亡,警方通過查閱死者的電腦和手機棍弄,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,464評論 3 395
  • 文/潘曉璐 我一進店門望薄,熙熙樓的掌柜王于貴愁眉苦臉地迎上來疟游,“玉大人,你說我怎么就攤上這事痕支“渑埃” “怎么了?”我有些...
    開封第一講書人閱讀 165,562評論 0 356
  • 文/不壞的土叔 我叫張陵卧须,是天一觀的道長另绩。 經常有香客問我,道長故慈,這世上最難降的妖魔是什么板熊? 我笑而不...
    開封第一講書人閱讀 58,893評論 1 295
  • 正文 為了忘掉前任,我火速辦了婚禮察绷,結果婚禮上干签,老公的妹妹穿的比我還像新娘。我一直安慰自己拆撼,他們只是感情好容劳,可當我...
    茶點故事閱讀 67,917評論 6 392
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著闸度,像睡著了一般竭贩。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上莺禁,一...
    開封第一講書人閱讀 51,708評論 1 305
  • 那天留量,我揣著相機與錄音,去河邊找鬼哟冬。 笑死楼熄,一個胖子當著我的面吹牛,可吹牛的內容都是我干的浩峡。 我是一名探鬼主播可岂,決...
    沈念sama閱讀 40,430評論 3 420
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼翰灾!你這毒婦竟也來了缕粹?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 39,342評論 0 276
  • 序言:老撾萬榮一對情侶失蹤纸淮,失蹤者是張志新(化名)和其女友劉穎平斩,沒想到半個月后,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體咽块,經...
    沈念sama閱讀 45,801評論 1 317
  • 正文 獨居荒郊野嶺守林人離奇死亡双戳,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 37,976評論 3 337
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片飒货。...
    茶點故事閱讀 40,115評論 1 351
  • 序言:一個原本活蹦亂跳的男人離奇死亡魄衅,死狀恐怖,靈堂內的尸體忽然破棺而出塘辅,到底是詐尸還是另有隱情晃虫,我是刑警寧澤,帶...
    沈念sama閱讀 35,804評論 5 346
  • 正文 年R本政府宣布扣墩,位于F島的核電站哲银,受9級特大地震影響,放射性物質發(fā)生泄漏呻惕。R本人自食惡果不足惜荆责,卻給世界環(huán)境...
    茶點故事閱讀 41,458評論 3 331
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望亚脆。 院中可真熱鬧做院,春花似錦、人聲如沸濒持。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,008評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽柑营。三九已至屈雄,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間官套,已是汗流浹背酒奶。 一陣腳步聲響...
    開封第一講書人閱讀 33,135評論 1 272
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留奶赔,地道東北人惋嚎。 一個月前我還...
    沈念sama閱讀 48,365評論 3 373
  • 正文 我出身青樓,卻偏偏與公主長得像纺阔,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子修然,可洞房花燭夜當晚...
    茶點故事閱讀 45,055評論 2 355

推薦閱讀更多精彩內容

  • 一個字符串 是一系列字符的集合笛钝,例如hello, world和albatross。Swift的字符串是String...
    BoomLee閱讀 2,401評論 0 3
  • String是例如"hello, world"愕宋,"albatross"這樣的有序的Character(字符)類型的...
    窮人家的孩紙閱讀 852評論 2 1
  • 程序不讀入內存就無法運行 程序保存在存儲設備中玻靡,通過有序地被讀出來實現(xiàn)運行,這個機制稱為“存儲程序方式”(程序內置...
    JunChow520閱讀 763評論 0 0
  • 34個對人生的回答讓你豁然開朗 2017-03-16溝通技巧 我們的性格應該有兩面:一面柔軟中贝,以便嘗透薄涼也能至真...
    ZhouWG閱讀 288評論 0 1
  • 結婚當天囤捻,對于新人來說是最忙碌的一天,同樣也是最喜慶的一天邻寿,所以在結婚當天一定需要注意很多細節(jié)蝎土,今天小編就針對于新...
    宇宙無敵666閱讀 191評論 0 0