1. 程式人生 > >IOS11,Swift4從入門到精通-05swift字串和字元

IOS11,Swift4從入門到精通-05swift字串和字元

本頁包含內容:

字串字面量 字面量中的特殊字元 初始化空字串 字串可變性 字串是值型別 使用字元 連線字串和字元 字串插值 Unicode 計算字元數量 訪問和修改字串 子字串 比較字串 字串的 Unicode 表示形式 字串是例如"hello, world","albatross"這樣的有序的Character(字元)型別的值的集合。通過String型別來表示。 一個String的內容可以用許多方式讀取,包括作為一個Character值的集合。

Swift 的String和Character型別提供了快速和相容 Unicode 的方式供你的程式碼使用。建立和操作字串的語法與 C 語言中字串操作相似,輕量並且易讀。 字串連線操作只需要簡單地通過+符號將兩個字串相連即可。與 Swift 中其他值一樣,能否更改字串的值,取決於其被定義為常量還是變數。你也可以在字串內插過程中使用字串插入常量、變數、字面量表達成更長的字串,這樣可以很容易的建立自定義的字串值,進行展示、儲存以及列印。

儘管語法簡易,但String型別是一種快速、現代化的字串實現。 每一個字串都是由編碼無關的 Unicode 字元組成,並支援訪問字元的多種 Unicode 表示形式(representations)。

注意: Swift 的String型別與 Foundation NSString類進行了無縫橋接。Foundation 也可以對String進行擴充套件,暴露在NSString中定義的方法。 這意味著,如果你在String中呼叫這些NSString的方法,將不用進行轉換。 更多關於在 Foundation 和 Cocoa 中使用String的資訊請檢視 Using Swift with Cocoa and Objective-C (Swift 4)。

字串字面量 你可以在程式碼裡使用一段預定義的字串值作為字串字面量。字串字面量是由一對雙引號包裹著的具有固定順序的字符集。

字串字面量可以用於為常量和變數提供初始值:

let someString = “Some string literal value” 注意someString常量通過字串字面量進行初始化,Swift 會推斷該常量為String型別。

多行字串字面量 如果你需要一個字串是跨越多行的,那就使用多行字串字面量 —— 由一對三個雙引號包裹著的具有固定順序的文字字符集:

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.” “”" 一個多行字串字面量包含了所有的在開啟和關閉引號(""")中的行。這個字元從開啟引號(""")之後的第一行開始,到關閉引號(""")之前為止。這就意味著字串開啟引號之後(""")或者結束引號(""")之前都沒有換行符號。(譯者:下面兩個字串其實是一樣的,雖然第二個使用了多行字串的形式)

let singleLineString = “These are the same.” let multilineString = “”" These are the same. “”" 如果你的程式碼中,多行字串字面量包含換行符的話,則多行字串字面量中也會包含換行符。如果你想換行,以便加強程式碼的可讀性,但是你又不想在你的多行字串字面量中出現換行符的話,你可以用在行尾寫一個反斜槓()作為續行符。

let softWrappedQuotation = “”" 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.” “”" 為了讓一個多行字串字面量開始和結束於換行符,請將換行寫在第一行和最後一行,例如:

let lineBreaks = “”"

This string starts with a line break. It also ends with a line break.

“”" 一個多行字串字面量能夠縮排來匹配周圍的程式碼。關閉引號(""")之前的空白字串告訴Swift編譯器其他各行多少空白字串需要忽略。然而,如果你在某行的前面寫的空白字串超出了關閉引號(""")之前的空白字串,則超出部分將被包含在多行字串字面量中。

在上面的例子中,儘管整個多行字串字面量都是縮排的(原始碼縮排),第一行和最後一行沒有以空白字串開始(實際的變數值)。中間一行的縮排用空白字串(原始碼縮排)比關閉引號(""")之前的空白字串多,所以,它的行首將有4個空格。

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

轉義字元\0(空字元)、\(反斜線)、\t(水平製表符)、\n(換行符)、\r(回車符)、"(雙引號)、’(單引號)。 Unicode 標量,寫成\u{n}(u為小寫),其中n為任意一到八位十六進位制數且可用的 Unicode 位碼。 下面的程式碼為各種特殊字元的使用示例。 wiseWords常量包含了兩個雙引號。 dollarSign、blackHeart和sparklingHeart常量演示了三種不同格式的 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 “”" “”"

初始化空字串 要建立一個空字串作為初始值,可以將空的字串字面量賦值給變數,也可以初始化一個新的String例項:

var emptyString = “” // 空字串字面量 var anotherEmptyString = String() // 初始化方法 // 兩個字串均為空並等價。 您可以通過檢查其Bool型別的isEmpty屬性來判斷該字串是否為空:

if emptyString.isEmpty { print(“Nothing to see here”) } // 列印輸出:“Nothing to see here”

字串可變性 您可以通過將一個特定字串分配給一個變數來對其進行修改,或者分配給一個常量來保證其不會被修改:

var variableString = “Horse” variableString += " and carriage" // variableString 現在為 “Horse and carriage”

let constantString = “Highlander” constantString += " and another Highlander" // 這會報告一個編譯錯誤 (compile-time error) - 常量字串不可以被修改。 注意: 在 Objective-C 和 Cocoa 中,您需要通過選擇兩個不同的類(NSString和NSMutableString)來指定字串是否可以被修改。

字串是值型別 Swift 的String型別是值型別。 如果您建立了一個新的字串,那麼當其進行常量、變數賦值操作,或在函式/方法中傳遞時,會進行值拷貝。 任何情況下,都會對已有字串值建立新副本,並對該新副本進行傳遞或賦值操作。 值型別在 結構體和列舉是值型別 中進行了詳細描述。

Swift 預設字串拷貝的方式保證了在函式/方法中傳遞的是字串的值。 很明顯無論該值來自於哪裡,都是您獨自擁有的。 您可以確信傳遞的字串不會被修改,除非你自己去修改它。

在實際編譯時,Swift 編譯器會優化字串的使用,使實際的複製只發生在絕對必要的情況下,這意味著您將字串作為值型別的同時可以獲得極高的效能。

使用字元 您可通過for-in迴圈來遍歷字串,獲取字串中每一個字元的值:

for character in “Dog!?” { print(character) } // D // o // g // ! // ? for-in迴圈在 For 迴圈 中進行了詳細描述。

另外,通過標明一個Character型別並用字元字面量進行賦值,可以建立一個獨立的字元常量或變數:

let exclamationMark: Character = “!” 字串可以通過傳遞一個值型別為Character的陣列作為自變數來初始化:

let catCharacters: [Character] = [“C”, “a”, “t”, “!”, “?”] let catString = String(catCharacters) print(catString) // 列印輸出:“Cat!?”

連線字串和字元 字串可以通過加法運算子(+)相加在一起(或稱“連線”)建立一個新的字串:

let string1 = “hello” let string2 = " there" var welcome = string1 + string2 // welcome 現在等於 “hello there” 您也可以通過加法賦值運算子 (+=) 將一個字串新增到一個已經存在字串變數上:

var instruction = “look over” instruction += string2 // instruction 現在等於 “look over there” 您可以用append()方法將一個字元附加到一個字串變數的尾部:

let exclamationMark: Character = “!” welcome.append(exclamationMark) // welcome 現在等於 “hello there!” 注意: 您不能將一個字串或者字元新增到一個已經存在的字元變數上,因為字元變數只能包含一個字元。

如果你需要使用多行字串字面量來拼接字串,並且你需要字串每一行都以換行符結尾,包括最後一行:

let badStart = “”" one two “”" let end = “”" three “”" print(badStart + end) // 列印兩行: // one // twothree

let goodStart = “”" one two

“”" print(goodStart + end) // 列印三行: // one // two // three 上面的程式碼,把 badStart 和 end 拼接起來的字串非我們想要的結果。因為 badStart 最後一行沒有換行符,它與 end 的第一行結合到了一起。相反的,goodStart 的每一行都以換行符結尾,所以它與 end 拼接的字串總共有三行,正如我們期望的那樣。

字串插值 字串插值是一種構建新字串的方式,可以在其中包含常量、變數、字面量和表示式。字串字面量和多行字串字面量都可以使用字串插值。 您插入的字串字面量的每一項都在以反斜線為字首的圓括號中:

let multiplier = 3 let message = “(multiplier) times 2.5 is (Double(multiplier) * 2.5)” // message 是 “3 times 2.5 is 7.5” 在上面的例子中,multiplier作為(multiplier)被插入到一個字串常量量中。 當建立字串執行插值計算時此佔位符會被替換為multiplier實際的值。

multiplier的值也作為字串中後面表示式的一部分。 該表示式計算Double(multiplier) * 2.5的值並將結果 (7.5) 插入到字串中。 在這個例子中,表示式寫為(Double(multiplier) * 2.5)幷包含在字串字面量中。

注意: 插值字串中寫在括號中的表示式不能包含非轉義反斜槓 (),並且不能包含回車或換行符。不過,插值字串可以包含其他字面量。

Unicode Unicode是一個國際標準,用於文字的編碼和表示。 它使您可以用標準格式表示來自任意語言幾乎所有的字元,並能夠對文字檔案或網頁這樣的外部資源中的字元進行讀寫操作。 Swift 的String和Character型別是完全相容 Unicode 標準的。

Unicode 標量 Swift 的String型別是基於 Unicode 標量 建立的。 Unicode 標量是對應字元或者修飾符的唯一的21位數字,例如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 A和FRONT-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轉換成了é。

在這兩種情況中,字母é代表了一個單一的 Swift 的Character值,同時代表了一個可擴充套件的字形群。 在第一種情況,這個字形群包含一個單一標量;而在第二種情況,它是包含兩個標量的字形群:

let eAcute: Character = “\u{E9}” // é let combinedEAcute: Character = “\u{65}\u{301}” // e 後面加上 ́ // eAcute 是 é, combinedEAcute 是 é 可擴充套件的字元群集是一個靈活的方法,用許多複雜的指令碼字元表示單一的Character值。 例如,來自朝鮮語字母表的韓語音節能表示為組合或分解的有序排列。 在 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 是 ??

計算字元數量 如果想要獲得一個字串中Character值的數量,可以使用count屬性:

let unusualMenagerie = “Koala ?, Snail ?, Penguin ?, Dromedary ?” print(“unusualMenagerie has (unusualMenagerie.count) characters”) // 列印輸出 “unusualMenagerie has 40 characters” 注意在 Swift 中,使用可拓展的字元群集作為Character值來連線或改變字串時,並不一定會更改字串的字元數量。

例如,如果你用四個字元的單詞cafe初始化一個新的字串,然後新增一個COMBINING ACTUE ACCENT(U+0301)作為字串的結尾。最終這個字串的字元數量仍然是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 標量。這意味著不同的字元以及相同字元的不同表示方式可能需要不同數量的記憶體空間來儲存。所以 Swift 中的字元在一個字串中並不一定佔用相同的記憶體空間數量。因此在沒有獲取字串的可擴充套件的字元群的範圍時候,就不能計算出字串的字元數量。如果您正在處理一個長字串,需要注意count屬性必須遍歷全部的 Unicode 標量,來確定字串的字元數量。

另外需要注意的是通過count屬性返回的字元數量並不總是與包含相同字元的NSString的length屬性相同。NSString的length屬性是利用 UTF-16 表示的十六位程式碼單元數字,而不是 Unicode 可擴充套件的字元群集。

訪問和修改字串 你可以通過字串的屬性和方法來訪問和修改它,當然也可以用下標語法完成。

字串索引 每一個String值都有一個關聯的索引(index)型別,String.Index,它對應著字串中的每一個Character的位置。

前面提到,不同的字元可能會佔用不同數量的記憶體空間,所以要知道Character的確定位置,就必須從String開頭遍歷每一個 Unicode 標量直到結尾。因此,Swift 的字串不能用整數(integer)做索引。

使用startIndex屬性可以獲取一個String的第一個Character的索引。使用endIndex屬性可以獲取最後一個Character的後一個位置的索引。因此,endIndex屬性不能作為一個字串的有效下標。如果String是空串,startIndex和endIndex是相等的。

通過呼叫 String 的 index(before:) 或 index(after:) 方法,可以立即得到前面或後面的一個索引。您還可以通過呼叫 index(_:offsetBy:) 方法來獲取對應偏移量的索引,這種方式可以避免多次呼叫 index(before:) 或 index(after:) 方法。

你可以使用下標語法來訪問 String 特定索引的 Character。

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,將引發一個執行時錯誤。

greeting[greeting.endIndex] // error greeting.index(after: endIndex) // error 使用 indices 屬性會建立一個包含全部索引的範圍(Range),用來在一個字串中訪問單個字元。

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:) 方法在任意一個確認的並遵循 Collection 協議的型別裡面,如上文所示是使用在 String 中,您也可以使用在 Array、Dictionary 和 Set中。

插入和刪除 呼叫 insert(_:at:) 方法可以在一個字串的指定索引插入一個字元,呼叫 insert(contentsOf:at:) 方法可以在一個字串的指定索引插入一個段字串。

var welcome = “hello” welcome.insert("!", at: welcome.endIndex) // welcome 變數現在等於 “hello!”

welcome.insert(contentsOf:" there", at: welcome.index(before: welcome.endIndex)) // welcome 變數現在等於 “hello there!” 呼叫 remove(at:) 方法可以在一個字串的指定索引刪除一個字元,呼叫 removeSubrange(_? 方法可以在一個字串的指定索引刪除一個子字串。

welcome.remove(at: welcome.index(before: welcome.endIndex)) // welcome 現在等於 “hello there”

let range = welcome.index(welcome.endIndex, offsetBy: -6)…<welcome.endIndex welcome.removeSubrange(range) // welcome 現在等於 “hello” 注意: 您可以使用 insert(:at:)、insert(contentsOf:at:)、remove(at:) 和 removeSubrange(? 方法在任意一個確認的並遵循 RangeReplaceableCollection 協議的型別裡面,如上文所示是使用在 String 中,您也可以使用在 Array、Dictionary 和 Set 中。

子字串 當你從字串中獲取一個子字串 —— 例如,使用下標或者 prefix(_? 之類的方法 —— 就可以得到一個 SubString 的例項,而非另外一個 String。Swift 裡的 SubString 絕大部分函式都跟 String 一樣,意味著你可以使用同樣的方式去操作 SubString 和 String。然而,跟 String 不同的是,你只有在短時間內需要操作字串時,才會使用 SubString。當你需要長時間儲存結果時,就把 SubString 轉化為 String 的例項:

let greeting = “Hello, world!” let index = greeting.index(of: “,”) ?? greeting.endIndex let beginning = greeting[…<index] // beginning 的值為 “Hello”

// 把結果轉化為 String 以便長期儲存。 let newString = String(beginning) 就像 String,每一個 SubString 都會在記憶體裡儲存字符集。而 String 和 SubString 的區別在於效能優化上,SubString 可以重用原 String 的記憶體空間,或者另一個 SubString 的記憶體空間(String 也有同樣的優化,但如果兩個 String 共享記憶體的話,它們就會相等)。這一優化意味著你在修改 String 和 SubString 之前都不需要消耗效能去複製記憶體。就像前面說的那樣,SubString 不適合長期儲存 —— 因為它重用了原 String 的記憶體空間,原 String 的記憶體空間必須保留直到它的 SubString 不再被使用為止。

上面的例子,greeting 是一個 String,意味著它在記憶體裡有一片空間儲存字符集。而由於 beginning 是 greeting 的 SubString,它重用了 greeting 的記憶體空間。相反,newString 是一個 String —— 它是使用 SubString 建立的,擁有一片自己的記憶體空間。下面的圖展示了他們之間的關係:

注意 String 和 SubString 都遵循 StringProtocol<//apple_ref/swift/intf/s:s14StringProtocolP> 協議,這意味著操作字串的函式使用 StringProtocol 會更加方便。你可以傳入 String 或 SubString 去呼叫函式。

比較字串 Swift 提供了三種方式來比較文字值:字串字元相等、字首相等和字尾相等。

字串/字元相等 字串/字元可以用等於操作符(==)和不等於操作符(!=),詳細描述在比較運算子:

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” 如果兩個字串(或者兩個字元)的可擴充套件的字形群集是標準相等的,那就認為它們是相等的。在這個情況下,即使可擴充套件的字形群集是有不同的 Unicode 標量構成的,只要它們有同樣的語言意義和外觀,就認為它們標準相等。

例如,LATIN SMALL LETTER E WITH ACUTE(U+00E9)就是標準相等於LATIN SMALL LETTER E(U+0065)後面加上COMBINING ACUTE ACCENT(U+0301)。這兩個字元群集都是表示字元é的有效方式,所以它們被認為是標準相等的:

// “Voulez-vous un café?” 使用 LATIN SMALL LETTER E WITH ACUTE let eAcuteQuestion = “Voulez-vous un caf\u{E9}?”

// “Voulez-vous un café?” 使用 LATIN SMALL LETTER E and COMBINING ACUTE ACCENT let combinedEAcuteQuestion = “Voulez-vous un caf\u{65}\u{301}?”

if eAcuteQuestion == combinedEAcuteQuestion { print(“These two strings are considered equal”) } // 列印輸出 “These two strings are considered equal” 相反,英語中的LATIN CAPITAL LETTER A(U+0041,或者A)不等於俄語中的CYRILLIC CAPITAL LETTER A(U+0410,或者A)。兩個字元看著是一樣的,但卻有不同的語言意義:

let latinCapitalLetterA: Character = “\u{41}”

let cyrillicCapitalLetterA: Character = “\u{0410}”

if latinCapitalLetterA != cyrillicCapitalLetterA { print(“These two characters are not equivalent”) } // 列印 “These two characters are not equivalent” 注意: 在 Swift 中,字串和字元並不區分地域(not locale-sensitive)。

字首/字尾相等 通過呼叫字串的hasPrefix(?/hasSuffix(:)方法來檢查字串是否擁有特定字首/字尾,兩個方法均接收一個String型別的引數,並返回一個布林值。

下面的例子以一個字串陣列表示莎士比亞話劇《羅密歐與朱麗葉》中前兩場的場景位置:

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(_:)方法來計算話劇中第一幕的場景數:

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(_:)方法來計算髮生在不同地方的場景數:

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(:)方法都是在每個字串中逐字元比較其可擴充套件的字元群集是否標準相等,詳細描述在字串/字元相等。

字串的 Unicode 表示形式 當一個 Unicode 字串被寫進文字檔案或者其他儲存時,字串中的 Unicode 標量會用 Unicode 定義的幾種編碼格式(encoding forms)編碼。每一個字串中的小塊編碼都被稱程式碼單元(code units)。這些包括 UTF-8 編碼格式(編碼字串為8位的程式碼單元), UTF-16 編碼格式(編碼字串位16位的程式碼單元),以及 UTF-32 編碼格式(編碼字串32位的程式碼單元)。

Swift 提供了幾種不同的方式來訪問字串的 Unicode 表示形式。 您可以利用for-in來對字串進行遍歷,從而以 Unicode 可擴充套件的字元群集的方式訪問每一個Character值。 該過程在 使用字元 中進行了描述。

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

UTF-8 程式碼單元集合 (利用字串的utf8屬性進行訪問) UTF-16 程式碼單元集合 (利用字串的utf16屬性進行訪問) 21位的 Unicode 標量值集合,也就是字串的 UTF-32 編碼格式 (利用字串的unicodeScalars屬性進行訪問) 下面由D,o,g,‼(DOUBLE EXCLAMATION MARK, Unicode 標量 U+203C)和?(DOG FACE,Unicode 標量為U+1F436)組成的字串中的每一個字元代表著一種不同的表示:

let dogString = “Dog‼?”

UTF-8 表示 您可以通過遍歷String的utf8屬性來訪問它的UTF-8表示。 其為String.UTF8View型別的屬性,UTF8View是無符號8位 (UInt8) 值的集合,每一個UInt8值都是一個字元的 UTF-8 表示:

Character D U+0044 o U+006F g U+0067 ‼ U+203C ? U+1F436 UTF-8 Code Unit 68 111 103 226 128 188 240 159 144 182 Position 0 1 2 3 4 5 6 7 8 9 for codeUnit in dogString.utf8 { print("(codeUnit) “, terminator: “”) } print(”") // 68 111 103 226 128 188 240 159 144 182 上面的例子中,前三個10進位制codeUnit值 (68, 111, 103) 代表了字元D、o和 g,它們的 UTF-8 表示與 ASCII 表示相同。 接下來的三個10進位制codeUnit值 (226, 128, 188) 是DOUBLE EXCLAMATION MARK的3位元組 UTF-8 表示。 最後的四個codeUnit值 (240, 159, 144, 182) 是DOG FACE的4位元組 UTF-8 表示。

UTF-16 表示 您可以通過遍歷String的utf16屬性來訪問它的UTF-16表示。 其為String.UTF16View型別的屬性,UTF16View是無符號16位 (UInt16) 值的集合,每一個UInt16都是一個字元的 UTF-16 表示:

Character D U+0044 o U+006F g U+0067 ‼ U+203C ? U+1F436 UTF-16 Code Unit 68 111 103 8252 55357 56374 Position 0 1 2 3 4 5 for codeUnit in dogString.utf16 { print("(codeUnit) “, terminator: “”) } print(”") // 68 111 103 8252 55357 56374 同樣,前三個codeUnit值 (68, 111, 103) 代表了字元D、o和g,它們的 UTF-16 程式碼單元和 UTF-8 完全相同(因為這些 Unicode 標量表示 ASCII 字元)。

第四個codeUnit值 (8252) 是一個等於十六進位制203C的的十進位制值。這個代表了DOUBLE EXCLAMATION MARK字元的 Unicode 標量值U+203C。這個字元在 UTF-16 中可以用一個程式碼單元表示。

第五和第六個codeUnit值 (55357和56374) 是DOG FACE字元的 UTF-16 表示。 第一個值為U+D83D(十進位制值為55357),第二個值為U+DC36(十進位制值為56374)。

Unicode 標量表示 您可以通過遍歷String值的unicodeScalars屬性來訪問它的 Unicode 標量表示。 其為UnicodeScalarView型別的屬性,UnicodeScalarView是UnicodeScalar型別的值的集合。 UnicodeScalar是21位的 Unicode 程式碼點。

每一個UnicodeScalar擁有一個value屬性,可以返回對應的21位數值,用UInt32來表示:

Character D U+0044 o U+006F g U+0067 ‼ U+203C ? U+1F436 Unicode Scalar Code Unit 68 111 103 8252 128054 Position 0 1 2 3 4 for scalar in dogString.unicodeScalars { print("(scalar.value) “, terminator: “”) } print(”") // 68 111 103 8252 128054 前三個UnicodeScalar值(68, 111, 103)的value屬性仍然代表字元D、o和g。 第四個codeUnit值(8252)仍然是一個等於十六進位制203C的十進位制值。這個代表了DOUBLE EXCLAMATION MARK字元的 Unicode 標量U+203C。

第五個UnicodeScalar值的value屬性,128054,是一個十六進位制1F436的十進位制表示。其等同於DOG FACE的 Unicode 標量U+1F436。

作為查詢它們的value屬性的一種替代方法,每個UnicodeScalar值也可以用來構建一個新的String值,比如在字串插值中使用:

for scalar in dogString.unicodeScalars { print("(scalar) ") } // D // o // g // ‼ // ?