字符串和字符 - Strings and Characters

2018-12-06 11:35 更新

字符串和字符(Strings and Characters)

String是例如“hello, world”,“海賊王” 這樣的有序的Character(字符)類型的值的集合,通過String類型來表示。

Swift 的StringCharacter類型提供了一個(gè)快速的,兼容 Unicode 的方式來處理代碼中的文本信息。創(chuàng)建和操作字符串的語法與 C 語言中字符串操作相似,輕量并且易讀。字符串連接操作只需要簡(jiǎn)單地通過+號(hào)將兩個(gè)字符串相連即可。與 Swift 中其他值一樣,能否更改字符串的值,取決于其被定義為常量還是變量。

盡管語法簡(jiǎn)易,但String類型是一種快速、現(xiàn)代化的字符串實(shí)現(xiàn)。每一個(gè)字符串都是由獨(dú)立編碼的 Unicode 字符組成,并提供了以不同 Unicode 表示(representations)來訪問這些字符的支持。

Swift 可以在常量、變量、字面量和表達(dá)式中進(jìn)行字符串插值操作,可以輕松創(chuàng)建用于展示、存儲(chǔ)和打印的自定義字符串。

注意:
Swift 的String類型與 Foundation NSString類進(jìn)行了無縫橋接。如果您利用 Cocoa 或 Cocoa Touch 中的 Foundation 框架進(jìn)行工作。所有NSString API 都可以調(diào)用您創(chuàng)建的任意String類型的值。除此之外,還可以使用本章介紹的String特性。您也可以在任意要求傳入NSString實(shí)例作為參數(shù)的 API 中使用String類型的值作為替代。更多關(guān)于在 Foundation 和 Cocoa 中使用String的信息請(qǐng)查看 Using Swift with Cocoa and Objective-C。

字符串字面量(String Literals)

您可以在您的代碼中包含一段預(yù)定義的字符串值作為字符串字面量。字符串字面量是由雙引號(hào) ("") 包裹著的具有固定順序的文本字符集。

字符串字面量可以用于為常量和變量提供初始值。

    let someString = "Some string literal value"

注意:
someString常量通過字符串字面量進(jìn)行初始化,Swift 因此推斷該常量為String類型。

字符串字面量可以包含以下特殊字符:

  • 轉(zhuǎn)義字符\0(空字符)、\\(反斜線)、\t(水平制表符)、\n(換行符)、\r(回車符)、\"(雙引號(hào))、\'(單引號(hào))。
  • Unicode 標(biāo)量,寫成\u{n}(u為小寫),其中n為任意的一到八位十六進(jìn)制數(shù)。

下面的代碼為各種特殊字符的使用示例。wiseWords常量包含了兩個(gè)轉(zhuǎn)移特殊字符 (雙括號(hào));dollarSignblackHeartsparklingHeart常量演示了三種不同格式的 Unicode 標(biāo)量:

    let wiseWords = "\"我是要成為海賊王的男人\" - 路飛"
    // "我是要成為海賊王的男人" - 路飛
    let dollarSign = "\u{24}"             // $,  Unicode 標(biāo)量 U+0024
    let blackHeart = "\u{2665}"           // ?,  Unicode 標(biāo)量 U+2665
    let sparklingHeart = "\u{1F496}"  // ????, Unicode 標(biāo)量 U+1F496

初始化空字符串 (Initializing an Empty String)

為了構(gòu)造一個(gè)很長(zhǎng)的字符串,可以創(chuàng)建一個(gè)空字符串作為初始值??梢詫⒖盏淖址置媪抠x值給變量,也可以初始化一個(gè)新的String實(shí)例:

    var emptyString = ""               // 空字符串字面量
    var anotherEmptyString = String()  // 初始化 String 實(shí)例
    // 兩個(gè)字符串均為空并等價(jià)。

您可以通過檢查其Boolean類型的isEmpty屬性來判斷該字符串是否為空:

    if emptyString.isEmpty {
        println("什么都沒有")
    }
    // 打印輸出:"什么都沒有"

字符串可變性 (String Mutability)

您可以通過將一個(gè)特定字符串分配給一個(gè)變量來對(duì)其進(jìn)行修改,或者分配給一個(gè)常量來保證其不會(huì)被修改:

    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) - 常量不可以被修改。

注意:
在 Objective-C 和 Cocoa 中,您通過選擇兩個(gè)不同的類(NSStringNSMutableString)來指定該字符串是否可以被修改,Swift 中的字符串是否可以修改僅通過定義的是變量還是常量來決定,實(shí)現(xiàn)了多種類型可變性操作的統(tǒng)一。

字符串是值類型(Strings Are Value Types)

Swift 的String類型是值類型。如果您創(chuàng)建了一個(gè)新的字符串,那么當(dāng)其進(jìn)行常量、變量賦值操作或在函數(shù)/方法中傳遞時(shí),會(huì)進(jìn)行值拷貝。任何情況下,都會(huì)對(duì)已有字符串值創(chuàng)建新副本,并對(duì)該新副本進(jìn)行傳遞或賦值操作。值類型在 結(jié)構(gòu)體和枚舉是值類型 中進(jìn)行了說明。

注意:
與 Cocoa 中的NSString不同,當(dāng)您在 Cocoa 中創(chuàng)建了一個(gè)NSString實(shí)例,并將其傳遞給一個(gè)函數(shù)/方法,或者賦值給一個(gè)變量,您傳遞或賦值的是該NSString實(shí)例的一個(gè)引用,除非您特別要求進(jìn)行值拷貝,否則字符串不會(huì)生成新的副本來進(jìn)行賦值操作。

Swift 默認(rèn)字符串拷貝的方式保證了在函數(shù)/方法中傳遞的是字符串的值。很明顯無論該值來自于哪里,都是您獨(dú)自擁有的。您可以放心您傳遞的字符串本身不會(huì)被更改。

在實(shí)際編譯時(shí),Swift 編譯器會(huì)優(yōu)化字符串的使用,使實(shí)際的復(fù)制只發(fā)生在絕對(duì)必要的情況下,這意味著您將字符串作為值類型的同時(shí)可以獲得極高的性能。

使用字符(Working with Characters)

Swift 的String類型表示特定序列的Character(字符) 類型值的集合。每一個(gè)字符值代表一個(gè) Unicode 字符。您可利用for-in循環(huán)來遍歷字符串中的每一個(gè)字符:

    for character in "Dog!????" {
        println(character)
    }
    // D
    // o
    // g
    // !
    // ????

for-in 循環(huán)在 For Loops 中進(jìn)行了詳細(xì)描述。

另外,通過標(biāo)明一個(gè)Character類型注解并通過字符字面量進(jìn)行賦值,可以建立一個(gè)獨(dú)立的字符常量或變量:

    let yenSign: Character = "¥"

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

通過調(diào)用全局countElements函數(shù),并將字符串作為參數(shù)進(jìn)行傳遞,可以獲取該字符串的字符數(shù)量。

    let unusualMenagerie = "Koala ????, Snail ????, Penguin ????, Dromedary ????"
    println("unusualMenagerie has \(countElements(unusualMenagerie)) characters")
    // 打印輸出:"unusualMenagerie has 40 characters"

注意:
不同的 Unicode 字符以及相同 Unicode 字符的不同表示方式可能需要不同數(shù)量的內(nèi)存空間來存儲(chǔ)。所以 Swift 中的字符在一個(gè)字符串中并不一定占用相同的內(nèi)存空間。因此字符串的長(zhǎng)度不得不通過迭代字符串中每一個(gè)字符的長(zhǎng)度來進(jìn)行計(jì)算。如果您正在處理一個(gè)長(zhǎng)字符串,需要注意countElements函數(shù)必須遍歷字符串中的字符以精準(zhǔn)計(jì)算字符串的長(zhǎng)度。另外需要注意的是通過countElements返回的字符數(shù)量并不總是與包含相同字符的NSStringlength屬性相同。NSStringlength屬性是基于利用 UTF-16 表示的十六位代碼單元數(shù)字,而不是基于 Unicode 字符。為了解決這個(gè)問題,NSStringlength屬性在被 Swift 的String訪問時(shí)會(huì)成為utf16count。

連接字符串和字符 (Concatenating Strings and Characters)

字符串可以通過加法運(yùn)算符(+)相加在一起(或稱“串聯(lián)”)并創(chuàng)建一個(gè)新的字符串:

    let string1 = "hello"
    let string2 = " there"
    var welcome = string1 + string2
    // welcome 現(xiàn)在等于 "hello there"

您也可以通過加法賦值運(yùn)算符 (+=) 將一個(gè)字符串添加到一個(gè)已經(jīng)存在字符串變量上:

    var instruction = "look over"
    instruction += string2
    // instruction 現(xiàn)在等于 "look over there"

你可以用將append方法將一個(gè)字符附加到一個(gè)字符串變量的尾部:

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

注意:
您不能將一個(gè)字符串或者字符添加到一個(gè)已經(jīng)存在的字符變量上,因?yàn)樽址兞恐荒馨粋€(gè)字符。

字符串插值 (String Interpolation)

字符串插值是一種構(gòu)建新字符串的方式,可以在其中包含常量、變量、字面量和表達(dá)式。您插入的字符串字面量的每一項(xiàng)都被包裹在以反斜線為前綴的圓括號(hào)中:

    let multiplier = 3
    let message = "\(multiplier) 乘以 2.5 是 \(Double(multiplier) * 2.5)"
    // message 是 "3 乘以 2.5 是 7.5"

在上面的例子中,multiplier作為\(multiplier)被插入到一個(gè)字符串字面量中。當(dāng)創(chuàng)建字符串執(zhí)行插值計(jì)算時(shí)此占位符會(huì)被替換為multiplier實(shí)際的值。

multiplier的值也作為字符串中后面表達(dá)式的一部分。該表達(dá)式計(jì)算Double(multiplier) * 2.5的值并將結(jié)果 (7.5) 插入到字符串中。在這個(gè)例子中,表達(dá)式寫為\(Double(multiplier) * 2.5)并包含在字符串字面量中。

注意:
插值字符串中寫在括號(hào)中的表達(dá)式不能包含非轉(zhuǎn)義雙引號(hào) (") 和反斜杠 (\),并且不能包含回車或換行符。

比較字符串 (Comparing Strings)

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

字符串相等 (String Equality)

如果兩個(gè)字符串以同一順序包含完全相同的字符,則認(rèn)為兩者字符串相等:

    let quotation = "我們是一樣一樣滴."
    let sameQuotation = "我們是一樣一樣滴."
    if quotation == sameQuotation {
        println("這兩個(gè)字符串被認(rèn)為是相同的")
    }
    // 打印輸出:"這兩個(gè)字符串被認(rèn)為是相同的"

前綴/后綴相等 (Prefix and Suffix Equality)

通過調(diào)用字符串的hasPrefix/hasSuffix方法來檢查字符串是否擁有特定前綴/后綴。兩個(gè)方法均需要以字符串作為參數(shù)傳入并傳出Boolean值。兩個(gè)方法均執(zhí)行基本字符串和前綴/后綴字符串之間逐個(gè)字符的比較操作。

下面的例子以一個(gè)字符串?dāng)?shù)組表示莎士比亞話劇《羅密歐與朱麗葉》中前兩場(chǎng)的場(chǎng)景位置:

    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方法來計(jì)算話劇中第一幕的場(chǎng)景數(shù):

    var act1SceneCount = 0
    for scene in romeoAndJuliet {
        if scene.hasPrefix("Act 1 ") {
            ++act1SceneCount
        }
    }
    println("There are \(act1SceneCount) scenes in Act 1")
    // 打印輸出:"There are 5 scenes in Act 1"

相似地,您可以用hasSuffix方法來計(jì)算發(fā)生在不同地方的場(chǎng)景數(shù):

    var mansionCount = 0
    var cellCount = 0
    for scene in romeoAndJuliet {
        if scene.hasSuffix("Capulet's mansion") {
            ++mansionCount
        } else if scene.hasSuffix("Friar Lawrence's cell") {
            ++cellCount
        }
    }
    println("\(mansionCount) mansion scenes; \(cellCount) cell scenes")
    // 打印輸出:"6 mansion scenes; 2 cell scenes”

大寫和小寫字符串(Uppercase and Lowercase Strings)

您可以通過字符串的uppercaseStringlowercaseString屬性來訪問大寫/小寫版本的字符串。

    import Foundation

    let normal = "Could you help me, please?"
    let shouty = normal.uppercaseString
    // shouty 值為 "COULD YOU HELP ME, PLEASE?"
    let whispered = normal.lowercaseString
    // whispered 值為 "could you help me, please?"

Unicode

Unicode 是一個(gè)國(guó)際標(biāo)準(zhǔn),用于文本的編碼和表示。它使您可以用標(biāo)準(zhǔn)格式表示來自任意語言幾乎所有的字符,并能夠?qū)ξ谋疚募蚓W(wǎng)頁這樣的外部資源中的字符進(jìn)行讀寫操作。

Swift 的字符串和字符類型是完全兼容 Unicode 標(biāo)準(zhǔn)的,它支持如下所述的一系列不同的 Unicode 編碼。

Unicode 術(shù)語(Unicode Terminology)

Unicode 中每一個(gè)字符都可以被解釋為一個(gè)或多個(gè) unicode 標(biāo)量。字符的 unicode 標(biāo)量是一個(gè)唯一的21位數(shù)字(和名稱),例如U+0061表示小寫的拉丁字母A ("a"),U+1F425表示小雞表情 ("????")

當(dāng) Unicode 字符串被寫進(jìn)文本文件或其他存儲(chǔ)結(jié)構(gòu)當(dāng)中,這些 unicode 標(biāo)量將會(huì)按照 Unicode 定義的集中格式之一進(jìn)行編碼。其包括UTF-8(以8位代碼單元進(jìn)行編碼) 和UTF-16(以16位代碼單元進(jìn)行編碼)。

字符串的 Unicode 表示(Unicode Representations of Strings)

Swift 提供了幾種不同的方式來訪問字符串的 Unicode 表示。

您可以利用for-in來對(duì)字符串進(jìn)行遍歷,從而以 Unicode 字符的方式訪問每一個(gè)字符值。該過程在 使用字符 中進(jìn)行了描述。

另外,能夠以其他三種 Unicode 兼容的方式訪問字符串的值:

  • UTF-8 代碼單元集合 (利用字符串的utf8屬性進(jìn)行訪問)
  • UTF-16 代碼單元集合 (利用字符串的utf16屬性進(jìn)行訪問)
  • 21位的 Unicode 標(biāo)量值集合 (利用字符串的unicodeScalars屬性進(jìn)行訪問)

下面由D``o``g``!????(DOG FACE,Unicode 標(biāo)量為U+1F436)組成的字符串中的每一個(gè)字符代表著一種不同的表示:

    let dogString = "Dog!????"

UTF-8

您可以通過遍歷字符串的utf8屬性來訪問它的UTF-8表示。其為UTF8View類型的屬性,UTF8View是無符號(hào)8位 (UInt8) 值的集合,每一個(gè)UInt8值都是一個(gè)字符的 UTF-8 表示:

    for codeUnit in dogString.utf8 {
        print("\(codeUnit) ")
    }
    print("\n")
    // 68 111 103 33 240 159 144 182

上面的例子中,前四個(gè)10進(jìn)制代碼單元值 (68, 111, 103, 33) 代表了字符D o g!,它們的 UTF-8 表示與 ASCII 表示相同。后四個(gè)代碼單元值 (240, 159, 144, 182) 是DOG FACE的4字節(jié) UTF-8 表示。

UTF-16

您可以通過遍歷字符串的utf16屬性來訪問它的UTF-16表示。其為UTF16View類型的屬性,UTF16View是無符號(hào)16位 (UInt16) 值的集合,每一個(gè)UInt16都是一個(gè)字符的 UTF-16 表示:

    for codeUnit in dogString.utf16 {
        print("\(codeUnit) ")
    }
    print("\n")
    // 68 111 103 33 55357 56374

同樣,前四個(gè)代碼單元值 (68, 111, 103, 33) 代表了字符D o g!,它們的 UTF-16 代碼單元和 UTF-8 完全相同。

第五和第六個(gè)代碼單元值 (55357 和 56374) 是DOG FACE字符的UTF-16 表示。第一個(gè)值為U+D83D(十進(jìn)制值為 55357),第二個(gè)值為U+DC36(十進(jìn)制值為 56374)。

Unicode 標(biāo)量 (Unicode Scalars)

您可以通過遍歷字符串的unicodeScalars屬性來訪問它的 Unicode 標(biāo)量表示。其為UnicodeScalarView類型的屬性, UnicodeScalarViewUnicodeScalar的集合。UnicodeScalar是21位的 Unicode 代碼點(diǎn)。

每一個(gè)UnicodeScalar擁有一個(gè)值屬性,可以返回對(duì)應(yīng)的21位數(shù)值,用UInt32來表示。

    for scalar in dogString.unicodeScalars {
        print("\(scalar.value) ")
    }
    print("\n")
    // 68 111 103 33 128054

同樣,前四個(gè)代碼單元值 (68, 111, 103, 33) 代表了字符D o g!。第五位數(shù)值,128054,是一個(gè)十六進(jìn)制1F436的十進(jìn)制表示。其等同于DOG FACE的Unicode 標(biāo)量 U+1F436。

作為查詢字符值屬性的一種替代方法,每個(gè)UnicodeScalar值也可以用來構(gòu)建一個(gè)新的字符串值,比如在字符串插值中使用:

    for scalar in dogString.unicodeScalars {
        println("\(scalar) ")
    }
    // D
    // o
    // g
    // !
    // ????
以上內(nèi)容是否對(duì)您有幫助:
在線筆記
App下載
App下載

掃描二維碼

下載編程獅App

公眾號(hào)
微信公眾號(hào)

編程獅公眾號(hào)