前言:
本篇文章的目的,在于记录学习过程,敦促自己,方便查看。练习工具:Playground
学习网站: swift51
本页内容包括:
字符串是例如
"hello, world","albatross"
这样的有序的Character(字符)
类型的值的集合。通过String
类型来表示。 一个>String>的内容可以用许多方式读取,包括作为一个Character
值的集合。
Swift
的String
和Character
类型提供了快速和兼容Unicode
的方式供你的代码使用。创建和操作字符串的语法与C
语言中字符串操作相似,轻量并且易读。 字符串连接操作只需要简单地通过+
符号将两个字符串相连即可。与
Swift
中其他值一样,能否更改字符串的值,取决于其被定义为常量还是变量。你也可以在字符串内插过程中使用字符串插入常量、变量、字面量表达成更长的字符串,这样可以很容易的创建自定义的字符串值,进行展示、存储以及打印。尽管语法简易,但
String
类型是一种快速、现代化的字符串实现。 每一个字符串都是由编码无关的Unicode
字符组成,并支持访问字符的多种Unicode
表示形式(representations)
。【注意】
Swift
的String
类型与 FoundationNSString
类进行了无缝桥接。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
值来连接或改变字符串时,并不一定
会更改字符串
的字符数量
。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
表示: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
表示:
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
来表示:
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 // ‼ // 🐶