String是例如"hello, world","albatross"這樣的有序的Character(字符)類型的值的集合。通過(guò)String類型來(lái)表示。
一個(gè)String的內(nèi)容可以用變量的方式讀取,它包括一個(gè)Character值的集合。
創(chuàng)建和操作字符串的語(yǔ)法與 C 語(yǔ)言中字符串操作相似,輕量并且易讀。
字符串連接操作只需要簡(jiǎn)單地通過(guò)+符號(hào)將兩個(gè)字符串相連即可。與 Swift 中其他值一樣,能否更改字符串的值,取決于其被定義為常量還是變量。也可以在字符串內(nèi)插過(guò)程中使用字符串插入常量、變量、字面量表達(dá)成更長(zhǎng)的字符串,這樣可以很容易的創(chuàng)建自定義的字符串值,進(jìn)行展示、存儲(chǔ)以及打印。
盡管語(yǔ)法簡(jiǎn)易,但String類型是一種快速、現(xiàn)代化的字符串實(shí)現(xiàn)。
每一個(gè)字符串都是由編碼無(wú)關(guān)的 Unicode 字符組成,并支持訪問(wèn)字符的多種 Unicode 表示形式(representations)。
注意:
Swift 的String類型與 FoundationNSString類進(jìn)行了無(wú)縫橋接。就像AnyObject類型中提到的一樣,在使用 Cocoa 中的 Foundation 框架時(shí),可以將創(chuàng)建的任何字符串的值轉(zhuǎn)換成NSString,并調(diào)用任意的NSStringAPI。也可以在任意要求傳入NSString實(shí)例作為參數(shù)的 API 中用String類型的值代替。
字符串字面量(String Literals)
可以在代碼中包含一段預(yù)定義的字符串值作為字符串字面量。字符串字面量是由雙引號(hào) ("") 包裹著的具有固定順序的文本字符集。
字符串字面量可以用于為常量和變量提供初始值:
let someString = "Some string literal value"
注意someString常量通過(guò)字符串字面量進(jìn)行初始化,Swift 會(huì)推斷該常量為String類型。
初始化空字符串 (Initializing an Empty String)
要?jiǎng)?chuàng)建一個(gè)空字符串作為初始值,可以將空的字符串字面量賦值給變量,也可以初始化一個(gè)新的String實(shí)例:
var emptyString = "" // 空字符串字面量
var anotherEmptyString = String() // 初始化方法
// 兩個(gè)字符串均為空并等價(jià)。
可以通過(guò)檢查其Boolean類型的isEmpty屬性來(lái)判斷該字符串是否為空:
if emptyString.isEmpty {
print("Nothing to see here")
}
// 打印輸出:"Nothing to see here"
字符串可變性 (String Mutability)
可以通過(guò)將一個(gè)特定字符串分配給一個(gè)變量來(lái)對(duì)其進(jìn)行修改,或者分配給一個(gè)常量來(lái)保證其不會(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 中,需要通過(guò)選擇兩個(gè)不同的類(NSString和NSMutableString)來(lái)指定字符串是否可以被修改。
字符串是值類型(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)行傳遞或賦值操作。
Swift 默認(rèn)字符串拷貝的方式保證了在函數(shù)/方法中傳遞的是字符串的值。
很明顯無(wú)論該值來(lái)自于哪里,都是獨(dú)自擁有的。
可以確信傳遞的字符串不會(huì)被修改,除非自己去修改它。
在實(shí)際編譯時(shí),Swift 編譯器會(huì)優(yōu)化字符串的使用,使實(shí)際的復(fù)制只發(fā)生在絕對(duì)必要的情況下,這意味著將字符串作為值類型的同時(shí)可以獲得極高的性能。
使用字符(Working with Characters)
可通過(guò)for-in循環(huán)來(lái)遍歷字符串中的characters屬性來(lái)獲取每一個(gè)字符的值:
for character in "Dog!??".characters {
print(character)
}
// D
// o
// g
// !
// ??
另外,通過(guò)標(biāo)明一個(gè)Character類型并用字符字面量進(jìn)行賦值,可以建立一個(gè)獨(dú)立的字符常量或變量:
let exclamationMark: Character = "!"
字符串可以通過(guò)傳入一個(gè)值類型為Character的數(shù)組作為自變量來(lái)初始化:
let catCharacters: [Character] = ["C", "a", "t", "!", "??"]
let catString = String(catCharacters)
print(catString)
// 打印輸出:"Cat!??"
連接字符串和字符 (Concatenating Strings and Characters)
字符串可以通過(guò)加法運(yùn)算符(+)相加在一起(或稱“連接”)創(chuàng)建一個(gè)新的字符串:
let string1 = "hello"
let string2 = " there"
var welcome = string1 + string2
// welcome 現(xiàn)在等于 "hello there"
也可以通過(guò)加法賦值運(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) times 2.5 is \(Double(multiplier) * 2.5)"
// message is "3 times 2.5 is 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)義反斜杠 (\\),并且不能包含回車或換行符。不過(guò),插值字符串可以包含其他字面量。
Unicode
Unicode 是一個(gè)國(guó)際標(biāo)準(zhǔn),用于文本的編碼和表示。
可以用標(biāo)準(zhǔn)格式表示來(lái)自任意語(yǔ)言幾乎所有的字符,并能夠?qū)ξ谋疚募蚓W(wǎng)頁(yè)這樣的外部資源中的字符進(jìn)行讀寫操作。
Swift 的String和Character類型是完全兼容 Unicode 標(biāo)準(zhǔn)的。
Unicode 標(biāo)量(Unicode Scalars)
Swift 的String類型是基于 Unicode 標(biāo)量 建立的。
Unicode 標(biāo)量是對(duì)應(yīng)字符或者修飾符的唯一的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 標(biāo)量不包括 Unicode 代理項(xiàng)(surrogate pair) 碼位,其碼位范圍是U+D800到U+DFFF。
注意不是所有的21位 Unicode 標(biāo)量都代表一個(gè)字符,因?yàn)橛幸恍?biāo)量是留作未來(lái)分配的。已經(jīng)代表一個(gè)典型字符的標(biāo)量都有自己的名字,例如上面例子中的LATIN SMALL LETTER A和FRONT-FACING BABY CHICK。
字符串字面量的特殊字符 (Special Characters in String Literals)
字符串字面量可以包含以下特殊字符:
- 轉(zhuǎn)義字符
\0(空字符)、\\\\(反斜線)、\t(水平制表符)、\n(換行符)、\r(回車符)、\"(雙引號(hào))、\'(單引號(hào))。 - Unicode 標(biāo)量,寫成
\u{n}(u為小寫),其中n為任意一到八位十六進(jìn)制數(shù)且可用的 Unicode 位碼。
下面的代碼為各種特殊字符的使用示例。
wiseWords常量包含了兩個(gè)雙引號(hào)。
dollarSign、blackHeart和sparklingHeart常量演示了三種不同格式的 Unicode 標(biāo)量:
let wiseWords = "\"Imagination is more important than knowledge\" - Einstein"
// "Imageination is more important than knowledge" - Enistein
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
可擴(kuò)展的字形群集(Extended Grapheme Clusters)
每一個(gè) Swift 的Character類型代表一個(gè)可擴(kuò)展的字形群。
一個(gè)可擴(kuò)展的字形群是一個(gè)或多個(gè)可生成人類可讀的字符 Unicode 標(biāo)量的有序排列。
舉個(gè)例子,字母é可以用單一的 Unicode 標(biāo)量é(LATIN SMALL LETTER E WITH ACUTE, 或者U+00E9)來(lái)表示。然而一個(gè)標(biāo)準(zhǔn)的字母e(LATIN SMALL LETTER E或者U+0065) 加上一個(gè)急促重音(COMBINING ACTUE ACCENT)的標(biāo)量(U+0301),這樣一對(duì)標(biāo)量就表示了同樣的字母é。
這個(gè)急促重音的標(biāo)量形象的將e轉(zhuǎn)換成了é。
在這兩種情況中,字母é代表了一個(gè)單一的 Swift 的Character值,同時(shí)代表了一個(gè)可擴(kuò)展的字形群。
在第一種情況,這個(gè)字形群包含一個(gè)單一標(biāo)量;而在第二種情況,它是包含兩個(gè)標(biāo)量的字形群:
let eAcute: Character = "\u{E9}" // é
let combinedEAcute: Character = "\u{65}\u{301}" // e 后面加上 ?
// eAcute 是 é, combinedEAcute 是 é
可擴(kuò)展的字符群集是一個(gè)靈活的方法,用許多復(fù)雜的腳本字符表示單一的Character值。
例如,來(lái)自朝鮮語(yǔ)字母表的韓語(yǔ)音節(jié)能表示為組合或分解的有序排列。
在 Swift 都會(huì)表示為同一個(gè)單一的Character值:
let precomposed: Character = "\u{D55C}" // ?
let decomposed: Character = "\u{1112}\u{1161}\u{11AB}" // ?, ?, ?
// precomposed 是 ?, decomposed 是 ?
可拓展的字符群集可以使包圍記號(hào)(例如COMBINING ENCLOSING CIRCLE或者U+20DD)的標(biāo)量包圍其他 Unicode 標(biāo)量,作為一個(gè)單一的Character值:
let enclosedEAcute: Character = "\u{E9}\u{20DD}"
// enclosedEAcute 是 é?
局部的指示符號(hào)的 Unicode 標(biāo)量可以組合成一個(gè)單一的Character值,例如REGIONAL INDICATOR SYMBOL LETTER U(U+1F1FA)和REGIONAL INDICATOR SYMBOL LETTER S(U+1F1F8):
let regionalIndicatorForUS: Character = "\u{1F1FA}\u{1F1F8}"
// regionalIndicatorForUS 是 ????
計(jì)算字符數(shù)量 (Counting Characters)
如果想要獲得一個(gè)字符串中Character值的數(shù)量,可以使用字符串的characters屬性的count屬性:
let unusualMenagerie = "Koala ??, Snail ??, Penguin ??, Dromedary ??"
print("unusualMenagerie has \(unusualMenagerie.characters.count) characters")
// 打印輸出 "unusualMenagerie has 40 characters"
注意在 Swift 中,使用可拓展的字符群集作為Character值來(lái)連接或改變字符串時(shí),并不一定會(huì)更改字符串的字符數(shù)量。
例如,如果用四個(gè)字符的單詞cafe初始化一個(gè)新的字符串,然后添加一個(gè)COMBINING ACTUE ACCENT(U+0301)作為字符串的結(jié)尾。最終這個(gè)字符串的字符數(shù)量仍然是4,因?yàn)榈谒膫€(gè)字符是é,而不是e:
var word = "cafe"
print("the number of characters in \(word) is \(word.characters.count)")
// 打印輸出 "the number of characters in cafe is 4"
word += "\u{301}" // COMBINING ACUTE ACCENT, U+0301
print("the number of characters in \(word) is \(word.characters.count)")
// 打印輸出 "the number of characters in café is 4"
注意:
可擴(kuò)展的字符群集可以組成一個(gè)或者多個(gè) Unicode 標(biāo)量。這意味著不同的字符以及相同字符的不同表示方式可能需要不同數(shù)量的內(nèi)存空間來(lái)存儲(chǔ)。所以 Swift 中的字符在一個(gè)字符串中并不一定占用相同的內(nèi)存空間數(shù)量。因此在沒(méi)有獲取字符串的可擴(kuò)展的字符群的范圍時(shí)候,就不能計(jì)算出字符串的字符數(shù)量。如果正在處理一個(gè)長(zhǎng)字符串,需要注意characters屬性必須遍歷全部的 Unicode 標(biāo)量,來(lái)確定字符串的字符數(shù)量。
另外需要注意的是通過(guò)
characters屬性返回的字符數(shù)量并不總是與包含相同字符的NSString的length屬性相同。NSString的length屬性是利用 UTF-16 表示的十六位代碼單元數(shù)字,而不是 Unicode 可擴(kuò)展的字符群集。作為佐證,當(dāng)一個(gè)NSString的length屬性被一個(gè)Swift的String值訪問(wèn)時(shí),實(shí)際上是調(diào)用了utf16Count。
訪問(wèn)和修改字符串 (Accessing and Modifying a String)
可以通字符串的屬性和方法來(lái)訪問(wèn)和讀取它,當(dāng)然也可以用下標(biāo)語(yǔ)法完成。
字符串索引 (String Indices)
每一個(gè)String值都有一個(gè)關(guān)聯(lián)的索引(index)類型,String.Index,它對(duì)應(yīng)著字符串中的每一個(gè)Character的位置。
前面提到,不同的字符可能會(huì)占用不同數(shù)量的內(nèi)存空間,所以要知道Character的確定位置,就必須從String開(kāi)頭遍歷每一個(gè) Unicode 標(biāo)量直到結(jié)尾。因此,Swift 的字符串不能用整數(shù)(integer)做索引。
使用startIndex屬性可以獲取一個(gè)String的第一個(gè)Character的索引。使用endIndex屬性可以獲取最后一個(gè)Character的后一個(gè)位置的索引。因此,endIndex屬性不能作為一個(gè)字符串的有效下標(biāo)。如果String是空串,startIndex和endIndex是相等的。
通過(guò)調(diào)用String.Index的predecessor()方法,可以立即得到前面一個(gè)索引,調(diào)用successor()方法可以立即得到后面一個(gè)索引。任何一個(gè)String的索引都可以通過(guò)鎖鏈作用的這些方法來(lái)獲取另一個(gè)索引,也可以調(diào)用advancedBy(_:)方法來(lái)獲取。但如果嘗試獲取出界的字符串索引,就會(huì)拋出一個(gè)運(yùn)行時(shí)錯(cuò)誤。
可以使用下標(biāo)語(yǔ)法來(lái)訪問(wèn)String特定索引的Character。
let greeting = "Guten Tag!"
greeting[greeting.startIndex]
// G
greeting[greeting.endIndex.predecessor()]
// !
greeting[greeting.startIndex.successor()]
// u
let index = greeting.startIndex.advancedBy(7)
greeting[index]
// a
試圖獲取越界索引對(duì)應(yīng)的Character,將引發(fā)一個(gè)運(yùn)行時(shí)錯(cuò)誤。
greeting[greeting.endIndex] // error
greeting.endIndex.successor() // error
使用characters屬性的indices屬性會(huì)創(chuàng)建一個(gè)包含全部索引的范圍(Range),用來(lái)在一個(gè)字符串中訪問(wèn)單個(gè)字符。
for index in greeting.characters.indices {
print("\(greeting[index]) ", terminator: " ")
}
// 打印輸出 "G u t e n T a g !"
插入和刪除 (Inserting and Removing)
調(diào)用insert(_:atIndex:)方法可以在一個(gè)字符串的指定索引插入一個(gè)字符。
var welcome = "hello"
welcome.insert("!", atIndex: welcome.endIndex)
// welcome now 現(xiàn)在等于 "hello!"
調(diào)用insertContentsOf(_:at:)方法可以在一個(gè)字符串的指定索引插入一個(gè)字符串。
welcome.insertContentsOf(" there".characters, at: welcome.endIndex.predecessor())
// welcome 現(xiàn)在等于 "hello there!"
調(diào)用removeAtIndex(_:)方法可以在一個(gè)字符串的指定索引刪除一個(gè)字符。
welcome.removeAtIndex(welcome.endIndex.predecessor())
// welcome 現(xiàn)在等于 "hello there"
調(diào)用removeRange(_:)方法可以在一個(gè)字符串的指定索引刪除一個(gè)子字符串。
let range = welcome.endIndex.advancedBy(-6)..<welcome.endIndex
welcome.removeRange(range)
// welcome 現(xiàn)在等于 "hello"
比較字符串 (Comparing Strings)
Swift 提供了三種方式來(lái)比較文本值:字符串字符相等、前綴相等和后綴相等。
字符串/字符相等 (String and Character Equality)
字符串/字符可以用等于操作符(==)和不等于操作符(!=):
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"
如果兩個(gè)字符串(或者兩個(gè)字符)的可擴(kuò)展的字形群集是標(biāo)準(zhǔn)相等的,那就認(rèn)為它們是相等的。在這個(gè)情況下,即使可擴(kuò)展的字形群集是有不同的 Unicode 標(biāo)量構(gòu)成的,只要它們有同樣的語(yǔ)言意義和外觀,就認(rèn)為它們標(biāo)準(zhǔn)相等。
例如,LATIN SMALL LETTER E WITH ACUTE(U+00E9)就是標(biāo)準(zhǔn)相等于LATIN SMALL LETTER E(U+0065)后面加上COMBINING ACUTE ACCENT(U+0301)。這兩個(gè)字符群集都是表示字符é的有效方式,所以它們被認(rèn)為是標(biāo)準(zhǔn)相等的:
// "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"
相反,英語(yǔ)中的LATIN CAPITAL LETTER A(U+0041,或者A)不等于俄語(yǔ)中的CYRILLIC CAPITAL LETTER A(U+0410,或者A)。兩個(gè)字符看著是一樣的,但卻有不同的語(yǔ)言意義:
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 中,字符串和字符并不區(qū)分區(qū)域。
前綴/后綴相等 (Prefix and Suffix Equality)
通過(guò)調(diào)用字符串的hasPrefix(_:)/hasSuffix(_:)方法來(lái)檢查字符串是否擁有特定前綴/后綴,兩個(gè)方法均接收一個(gè)String類型的參數(shù),并返回一個(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"
]
可以調(diào)用hasPrefix(_:)方法來(lái)計(jì)算話劇中第一幕的場(chǎng)景數(shù):
var act1SceneCount = 0
for scene in romeoAndJuliet {
if scene.hasPrefix("Act 1 ") {
++act1SceneCount
}
}
print("There are \(act1SceneCount) scenes in Act 1")
// 打印輸出 "There are 5 scenes in Act 1"
相似地,可以用hasSuffix(_:)方法來(lái)計(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
}
}
print("\(mansionCount) mansion scenes; \(cellCount) cell scenes")
// 打印輸出 "6 mansion scenes; 2 cell scenes"
注意:
hasPrefix(_:)和hasSuffix(_:)方法都是在每個(gè)字符串中逐字符比較其可擴(kuò)展的字符群集是否標(biāo)準(zhǔn)相等。
字符串的 Unicode 表示形式(Unicode Representations of Strings)
當(dāng)一個(gè) Unicode 字符串被寫進(jìn)文本文件或者其他儲(chǔ)存時(shí),字符串中的 Unicode 標(biāo)量會(huì)用 Unicode 定義的幾種編碼格式編碼。每一個(gè)字符串中的小塊編碼都被稱為代碼單元。這些包括 UTF-8 編碼格式(編碼字符串為8位的代碼單元), UTF-16 編碼格式(編碼字符串位16位的代碼單元),以及 UTF-32 編碼格式(編碼字符串32位的代碼單元)。
Swift 提供了幾種不同的方式來(lái)訪問(wèn)字符串的 Unicode 表示形式。
可以利用for-in來(lái)對(duì)字符串進(jìn)行遍歷,從而以 Unicode 可擴(kuò)展的字符群集的方式訪問(wèn)每一個(gè)Character值。
另外,能夠以其他三種 Unicode 兼容的方式訪問(wèn)字符串的值:
- UTF-8 代碼單元集合 (利用字符串的
utf8屬性進(jìn)行訪問(wèn)) - UTF-16 代碼單元集合 (利用字符串的
utf16屬性進(jìn)行訪問(wèn)) - 21位的 Unicode 標(biāo)量值集合,也就是字符串的 UTF-32 編碼格式 (利用字符串的
unicodeScalars屬性進(jìn)行訪問(wèn))
下面由D o g ?(DOUBLE EXCLAMATION MARK, Unicode 標(biāo)量 U+203C)和??(DOG FACE,Unicode 標(biāo)量為U+1F436)組成的字符串中的每一個(gè)字符代表著一種不同的表示:
let dogString = "Dog???"
UTF-8 表示
可以通過(guò)遍歷String的utf8屬性來(lái)訪問(wèn)它的UTF-8表示。
其為String.UTF8View類型的屬性,UTF8View是無(wú)符號(hào)8位 (UInt8) 值的集合,每一個(gè)UInt8值都是一個(gè)字符的 UTF-8 表示:
<table style='text-align:center'>
<tr height="77">
<td>Character</td>
<td>D
U+0044</td>
<td>o
U+006F</td>
<td>g
U+0067</td>
<td colspan="3">?
U+203C</td>
<td colspan="4">??
U+1F436</td>
</tr>
<tr height="77">
<td height="77">UTF-8
Code Unit</td>
<td>68</td>
<td>111</td>
<td>103</td>
<td>226</td>
<td>128</td>
<td>188</td>
<td>240</td>
<td>159</td>
<td>144</td>
<td>182</td>
</tr>
<tr>
<td height="77">Position</td>
<td>0</td>
<td>1</td>
<td>2</td>
<td>3</td>
<td>4</td>
<td>5</td>
<td>6</td>
<td>7</td>
<td>8</td>
<td>9</td>
</tr>
</table>
for codeUnit in dogString.utf8 {
print("\(codeUnit) ", terminator: "")
}
print("")
// 68 111 103 226 128 188 240 159 144 182
上面的例子中,前三個(gè)10進(jìn)制codeUnit值 (68, 111, 103) 代表了字符D、o和 g,它們的 UTF-8 表示與 ASCII 表示相同。
接下來(lái)的三個(gè)10進(jìn)制codeUnit值 (226, 128, 188) 是DOUBLE EXCLAMATION MARK的3字節(jié) UTF-8 表示。
最后的四個(gè)codeUnit值 (240, 159, 144, 182) 是DOG FACE的4字節(jié) UTF-8 表示。
UTF-16 表示
可以通過(guò)遍歷String的utf16屬性來(lái)訪問(wèn)它的UTF-16表示。
其為String.UTF16View類型的屬性,UTF16View是無(wú)符號(hào)16位 (UInt16) 值的集合,每一個(gè)UInt16都是一個(gè)字符的 UTF-16 表示:
<table style='text-align:center'>
<tr height="77">
<td>Character</td>
<td>D
U+0044</td>
<td>o
U+006F</td>
<td>g
U+0067</td>
<td>?
U+203C</td>
<td colspan="2">??
U+1F436</td>
</tr>
<tr height="77">
<td height="77">UTF-16
Code Unit</td>
<td>68</td>
<td>111</td>
<td>103</td>
<td>8252</td>
<td>55357</td>
<td>56374</td>
</tr>
<tr>
<td height="77">Position</td>
<td>0</td>
<td>1</td>
<td>2</td>
<td>3</td>
<td>4</td>
<td>5</td>
</tr>
</table>
for codeUnit in dogString.utf16 {
print("\(codeUnit) ", terminator: "")
}
print("")
// 68 111 103 8252 55357 56374
同樣,前三個(gè)codeUnit值 (68, 111, 103) 代表了字符D、o和g,它們的 UTF-16 代碼單元和 UTF-8 完全相同(因?yàn)檫@些 Unicode 標(biāo)量表示 ASCII 字符)。
第四個(gè)codeUnit值 (8252) 是一個(gè)等于十六進(jìn)制203C的的十進(jìn)制值。這個(gè)代表了DOUBLE EXCLAMATION MARK字符的 Unicode 標(biāo)量值U+203C。這個(gè)字符在 UTF-16 中可以用一個(gè)代碼單元表示。
第五和第六個(gè)codeUnit值 (55357和56374) 是DOG FACE字符的 UTF-16 表示。
第一個(gè)值為U+D83D(十進(jìn)制值為55357),第二個(gè)值為U+DC36(十進(jìn)制值為56374)。
Unicode 標(biāo)量表示 (Unicode Scalars Representation)
可以通過(guò)遍歷String值的unicodeScalars屬性來(lái)訪問(wèn)它的 Unicode 標(biāo)量表示。
其為UnicodeScalarView類型的屬性,UnicodeScalarView是UnicodeScalar的集合。
UnicodeScalar是21位的 Unicode 代碼點(diǎn)。
每一個(gè)UnicodeScalar擁有一個(gè)value屬性,可以返回對(duì)應(yīng)的21位數(shù)值,用UInt32來(lái)表示:
<table style='text-align:center'>
<tr height="77">
<td>Character</td>
<td>D
U+0044</td>
<td>o
U+006F</td>
<td>g
U+0067</td>
<td>?
U+203C</td>
<td>??
U+1F436</td>
</tr>
<tr height="77">
<td height="77">UTF-16
Code Unit</td>
<td>68</td>
<td>111</td>
<td>103</td>
<td>8252</td>
<td>128054</td>
</tr>
<tr>
<td height="77">Position</td>
<td>0</td>
<td>1</td>
<td>2</td>
<td>3</td>
<td>4</td>
</tr>
</table>
for scalar in dogString.unicodeScalars {
print("\(scalar.value) ", terminator: "")
}
print("")
// 68 111 103 8252 128054
前三個(gè)UnicodeScalar值(68, 111, 103)的value屬性仍然代表字符D、o和g。
第四個(gè)codeUnit值(8252)仍然是一個(gè)等于十六進(jìn)制203C的十進(jìn)制值。這個(gè)代表了DOUBLE EXCLAMATION MARK字符的 Unicode 標(biāo)量U+203C。
第五個(gè)UnicodeScalar值的value屬性,128054,是一個(gè)十六進(jìn)制1F436的十進(jìn)制表示。其等同于DOG FACE的 Unicode 標(biāo)量U+1F436。
作為查詢它們的value屬性的一種替代方法,每個(gè)UnicodeScalar值也可以用來(lái)構(gòu)建一個(gè)新的String值,比如在字符串插值中使用:
for scalar in dogString.unicodeScalars {
print("\(scalar) ")
}
// D
// o
// g
// ?
// ??