Swift-字符串和字符

1. 字符串

  • 在 Swift 中 String 類(lèi)型是值類(lèi)型。
  • 如果你創(chuàng)建了一個(gè)新的字符串,那么當(dāng)其進(jìn)行常量、變量賦值操作,或在函數(shù)/方法中傳遞時(shí),會(huì)進(jìn)行值拷貝。
  • 在前述任一情況下,都會(huì)對(duì)已有字符串值創(chuàng)建新副本,并對(duì)該新副本而非原始字符串進(jìn)行傳遞或賦值操作

1.1 初始化空字符串

// 兩個(gè)字符串均為空并等價(jià)。
var emptyString = ""    //  空字符串字面量
var anotherEmptyString = String()   //  初始化方法
  • 你可以通過(guò)檢查 Bool 類(lèi)型的 isEmpty 屬性來(lái)判斷該字符串是否為空:
if emptyString.isEmpty {
    print("Nothing to see here")
}   //  打印輸出:“Nothing to see here”

1.2 字符串可變性

var variableString = "Horse"
variableString += " and carriage"   // variableString 現(xiàn)在為 "Horse and carriage"

let constantString = "Highlander"
constantString += " and another Highlander" // 這會(huì)報(bào)告一個(gè)編譯錯(cuò)誤(compile-time error) - 常量字符串不可以被修改。

1.3 連接字符串和字符

  • 字符串可以通過(guò)加法運(yùn)算符(+)相加在一起(或稱(chēng)“連接”)創(chuàng)建一個(gè)新的字符串。
  • 可以通過(guò)加法賦值運(yùn)算符(+=)將一個(gè)字符串添加到一個(gè)已經(jīng)存在字符串變量上。
  • 可以用 append() 方法將一個(gè)字符附加到一個(gè)字符串變量的尾部。
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"

let exclamationMark: Character = "!"
welcome.append(exclamationMark) //  welcome 現(xiàn)在等于 "hello there!"

1.4 字符串插值

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

1.5 計(jì)算字符數(shù)量

let unusualMenagerie = "Koala ??, Snail ??, Penguin ??, Dromedary ??"
print("unusualMenagerie has \(unusualMenagerie.count) characters")
// 打印輸出“unusualMenagerie has 40 characters”

1.6 訪問(wèn)和修改字符串

1.6.1 字符串索引

  • 每一個(gè) String 值都有一個(gè)關(guān)聯(lián)的索引(index)類(lèi)型,String.Index,它對(duì)應(yīng)著字符串中的每一個(gè) Character 的位置。
  • 使用 startIndex 屬性可以獲取一個(gè) String 的第一個(gè) Character 的索引。
  • 使用 endIndex 屬性可以獲取最后一個(gè) Character 的后一個(gè)位置的索引。
  • 如果 String 是空串,startIndex 和 endIndex 是相等的。
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

通過(guò)調(diào)用 String 的 index(before:) 或 index(after:) 方法,可以立即得到前面或后面的一個(gè)索引。
你還可以通過(guò)調(diào)用 index(_:offsetBy:) 方法來(lái)獲取對(duì)應(yīng)偏移量的索引,這種方式可以避免多次調(diào)用 index(before:) 或 index(after:) 方法。

  • 使用 indices 屬性會(huì)創(chuàng)建一個(gè)包含全部索引的范圍(Range),用來(lái)在一個(gè)字符串中訪問(wèn)單個(gè)字符。
for index in greeting.indices {
   print("\(greeting[index]) ", terminator:" ")
}   //  打印輸出“G u t e n   T a g ! ”

注意:
你可以使用 startIndex 和 endIndex 屬性或者 index(before:) 、index(after:) 和 index(_:offsetBy:) 方法在任意一個(gè)確認(rèn)的并遵循 Collection 協(xié)議的類(lèi)型里面,如上文所示是使用在 String 中,你也可以使用在 Array、Dictionary 和 Set 中。

1.6.2 插入和刪除

  • 調(diào)用 insert(_:at:) 方法可以在一個(gè)字符串的指定索引插入一個(gè)字符。
  • 調(diào)用 insert(contentsOf:at:) 方法可以在一個(gè)字符串的指定索引插入一個(gè)段字符串。
var welcome = "hello"
welcome.insert("!", at: welcome.endIndex)   // welcome 變量現(xiàn)在等于 "hello!"

welcome.insert(contentsOf:" there", at: welcome.index(before: welcome.endIndex))    // welcome 變量現(xiàn)在等于 "hello there!"
  • 調(diào)用 remove(at:) 方法可以在一個(gè)字符串的指定索引刪除一個(gè)字符。
  • 調(diào)用 removeSubrange(_:) 方法可以在一個(gè)字符串的指定索引刪除一個(gè)子字符串。
welcome.remove(at: welcome.index(before: welcome.endIndex)) // welcome 現(xiàn)在等于 "hello there"

let range = welcome.index(welcome.endIndex, offsetBy: -6)..<welcome.endIndex
welcome.removeSubrange(range)   // welcome 現(xiàn)在等于 "hello"

注意:
你可以使用 insert(:at:)、insert(contentsOf:at:)、remove(at:) 和 removeSubrange(:) 方法在任意一個(gè)確認(rèn)的并遵循 RangeReplaceableCollection 協(xié)議的類(lèi)型里面,如上文所示是使用在 String 中,你也可以使用在 Array、Dictionary 和 Set 中。

1.7 子字符串

  • 當(dāng)你從字符串中獲取一個(gè)子字符串,可以使用下標(biāo)或者 prefix(_:) 之類(lèi)的方法,就可以得到一個(gè) SubString 的實(shí)例,而非另外一個(gè) String。
  • Swift 里的 SubString 絕大部分函數(shù)都跟 String 一樣,意味著你可以使用同樣的方式去操作 SubString 和 String。
  • 跟 String 不同的是,你只有在短時(shí)間內(nèi)需要操作字符串時(shí),才會(huì)使用 SubString。
  • 當(dāng)你需要長(zhǎng)時(shí)間保存結(jié)果時(shí),就把 SubString 轉(zhuǎn)化為 String 的實(shí)例。(因?yàn)樗赜昧嗽?String 的內(nèi)存空間,原 String 的內(nèi)存空間必須保留直到它的 SubString 不再被使用為止。)
let greeting = "Hello, world!"
let index = greeting.firstIndex(of: ",") ?? greeting.endIndex
let beginning = greeting[..<index]
// beginning 的值為 "Hello"

// 把結(jié)果轉(zhuǎn)化為 String 以便長(zhǎng)期存儲(chǔ)。
let newString = String(beginning)
String 和 SubString 的區(qū)別在于:
    性能優(yōu)化上,SubString 可以重用原 String 的內(nèi)存空間,或者另一個(gè) SubString 的內(nèi)存空間(String 也有同樣的優(yōu)化,但如果兩個(gè) String 共享內(nèi)存的話,它們就會(huì)相等)。這一優(yōu)化意味著你在修改 String 和 SubString 之前都不需要消耗性能去復(fù)制內(nèi)存。就像前面說(shuō)的那樣,SubString 不適合長(zhǎng)期存儲(chǔ) —— 因?yàn)樗赜昧嗽?String 的內(nèi)存空間,原 String 的內(nèi)存空間必須保留直到它的 SubString 不再被使用為止。

1.8 字符串比較

Swift 提供了三種方式來(lái)比較文本值:

  • 字符串字符相等
  • 前綴相等
  • 后綴相等

1.8.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”
}

1.8.2 前綴相等

調(diào)用字符串的 hasPrefix(_:) 方法來(lái)檢查字符串是否擁有特定前綴,方法接收一個(gè) String 類(lèi)型的參數(shù),并返回一個(gè)布爾值。

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"
]

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”

1.8.3 后綴相等

調(diào)用字符串的 hasSuffix(_:) 方法來(lái)檢查字符串是否擁有特定后綴,方法接收一個(gè) String 類(lèi)型的參數(shù),并返回一個(gè)布爾值。

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"
]

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”

2. 字符

  • 可通過(guò) for-in 循環(huán)來(lái)遍歷字符串,獲取字符串中每一個(gè)字符的值:
for character in "Dog!" {
    print(character)
}
// D
// o
// g
// !
  • 通過(guò)標(biāo)明一個(gè) Character 類(lèi)型并用字符字面量進(jìn)行賦值,可以建立一個(gè)獨(dú)立的字符常量或變量:
let exclamationMark: Character = "!"
  • 字符串可以通過(guò)傳遞一個(gè)值類(lèi)型為 Character 的數(shù)組作為自變量來(lái)初始化:
let catCharacters: [Character] = ["C", "a", "t", "!"]
let catString = String(catCharacters)
print(catString)    //  打印輸出:“Cat!”

3. 字符串的 Unicode 表示形式

當(dāng)一個(gè) Unicode 字符串被寫(xiě)進(jìn)文本文件或者其他儲(chǔ)存時(shí),字符串中的 Unicode 標(biāo)量會(huì)用 Unicode 定義的幾種 編碼格式(encoding forms) 編碼。每一個(gè)字符串中的小塊編碼都被稱(chēng) 代碼單元(code units) 。

  • UTF-8 編碼格式:編碼字符串為 8 位的代碼單元。
  • UTF-16 編碼格式:編碼字符串位 16 位的代碼單元。
  • UTF-32 編碼格式:編碼字符串32位的代碼單元。
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容