继续学习Swift文档,从上一章节:基本的操做,咱们学习了Swift上基本的一些运算符操做,基本上跟C、OC上的运算符同样;不过,在Swift上有一些特有的运算符,能够简化代码,如??操做符、...操做符、..<操做符和单边值域,不熟悉的朋友能够到上一章节去看这部份内容(在七、八、9三个小节)。如今,咱们学习Swift的字符串和字符相关的内容。因为篇幅较长,这里分篇来记录,接下来,开始吧!html
这一章节内容比较简单,已经熟悉的朋友能够跳过,进入下一章节:集合类型web
字符串是一系列字符,如“hello, world”或“albatross”。Swift字符串由字符串类型表示。字符串的内容能够经过各类方式访问,包括做为字符值的集合访问。swift
Swift的字符串和字符类型提供了一种快速、兼容unicode的方式来处理代码中的文本。字符串的语法建立和操纵轻便,可读性强,与字符串的语法相似于c字符串链接很是简单,只需将两个字符串+操做符,和字符串可变性由常量或变量之间选择,就像任何其余价值迅速。还可使用字符串将常量、变量、文本和表达式插入到更长的字符串中,这个过程称为字符串插值。这使得为显示、存储和打印建立自定义字符串值变得很容易。api
尽管语法简单,Swift的字符串类型是一种快速、现代的字符串实现。每一个字符串都由与编码无关的Unicode字符组成,并支持以各类Unicode表示形式访问这些字符。数组
Swift的字符串类型经过Foundation的NSString类进行链接。Foundation还扩展了String以公开NSString定义的方法。这意味着,若是你导入Foundation,你能够在字符串上访问那些NSString方法而不须要强制转换。性能优化
有关在Foundation和Cocoa中使用String的更多信息,请参见String和NSString之间架桥。bash
能够在代码中以字符串文本的形式包含预约义的字符串值。字符串文字是由双引号(")包围的字符序列。app
使用字符串文字做为常量或变量的初始值:ide
let someString = "Some string literal value"
复制代码
注意,Swift为someString常量推断出一种字符串类型,由于它是用字符串文字值初始化的。函数
若是你须要一个跨越几行的字符串,使用一个多行字符串文本-由三个双引号包围的字符序列:
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在全部其余行以前忽略哪些空白。可是,若是除了在结束引号以前还在一行的开始处添加空格,那么该空格就包含在内。
在上面的示例中,即便整个多行字符串是缩进的,字符串的第一行和最后一行并不以任何空格开始。中间的一行比结束引号有更多的缩进,因此它以额外的四空格缩进开始。
字符串中可包含如下特殊的字符:
下面的代码显示了这些特殊字符的四个示例。wiseWords常量包含两个转义双引号。dollarSign、blackHeart和sparklingHeart常量演示了Unicode标量格式:
let wiseWords = "\"Imagination is more important than knowledge\" - Einstein"
// "Imagination is more important than knowledge" - Einstein
let dollarSign = "\u{24}" // $, Unicode scalar U+0024
let blackHeart = "\u{2665}" // ♥, Unicode scalar U+2665
let sparklingHeart = "\u{1F496}" // 💖, Unicode scalar U+1F496
复制代码
由于多行字符串字面量使用三个双引号而不是一个,因此能够在多行字符串字面量中包含一个双引号(")而不用转义。要在多行字符串中包含文本""",必须转义至少一个引号。例如:
let threeDoubleQuotationMarks = """ Escaping the first quotation mark \""" Escaping all three quotation marks \"\"\" """
复制代码
能够在扩展分隔符中放置字符串文字,以便在字符串中包含特殊字符而不调用其效果。您将字符串放在引号(")中,并用数字符号(#)包围它。例如,打印字符串文本#" line1 \nLine 2"#将打印换行转义序列(\n),而不是跨两行打印字符串。
若是须要字符串文本中的字符的特殊效果,则匹配转义字符()后面的字符串中的数字符号数量。例如,若是您的字符串是#"Line 1\nLine 2"#,而且您但愿换行,您可使用#"Line 1#nLine 2"#来代替。相似地,###"Line1###nLine2"###也会中断该行。
使用扩展分隔符建立的字符串文本也能够是多行字符串文本。可使用扩展的分隔符将文本"""包含在多行字符串中,覆盖结束文本的默认行为。例如:
let threeMoreDoubleQuotationMarks = #"""
Here are three more double quotes: """ """#
复制代码
要建立一个空字符串值做为构建更长的字符串的起点,能够为变量分配一个空字符串文字,或者使用初始化器语法初始化一个新的字符串实例:
var emptyString = "" // empty string literal
var anotherEmptyString = String() // initializer syntax
// these two strings are both empty, and are equivalent to each other
复制代码
经过检查一个字符串的布尔值isEmpty属性来判断它是否为空:
if emptyString.isEmpty {
print("Nothing to see here")
}
// Prints "Nothing to see here"
复制代码
你能够经过将一个特定的字符串赋值给一个变量(在这种状况下它能够被修改),或者赋值给一个常量(在这种状况下它不能被修改)来指示它是否能够被修改(或改变):
var variableString = "Horse"
variableString += " and carriage"
// variableString is now "Horse and carriage"
let constantString = "Highlander"
constantString += " and another Highlander"
// this reports a compile-time error - a constant string cannot be modified
复制代码
注意 这种方法不一样于Objective-C和Cocoa中的字符串改变,在那里你能够在两个类(NSString和NSMutableString)之间进行选择,以指示字符串是否能够被改变。
Swift的字符串类型是一种值类型。若是您建立了一个新的字符串值,当它被传递给一个函数或方法时,或者当它被分配给一个常量或变量时,该字符串值会被复制。在每种状况下,都会建立现有字符串值的新副本,并传递或分配新副本,而不是原始值。值类型在结构体和枚举是值类型中有描述。
Swift的copy-by-default字符串行为确保了当一个函数或方法传递给你一个字符串值时,无论它来自哪里,你都清楚地拥有这个字符串值。您能够确信,您传递的字符串不会被修改,除非您本身修改它。
在幕后,Swift的编译器优化了字符串的使用,这样实际的复制只在绝对必要的时候才会发生。这意味着当您使用字符串做为值类型时,老是可以得到良好的性能。
你能够经过for-in循环遍历字符串来访问单个字符的值:
for character in "Dog!🐶" {
print(character)
}
// D
// o
// g
// !
// 🐶
复制代码
for-in循环参见For-In Loops。
或者,您能够经过提供字符类型注释,从单字符字符串文本建立独立的字符常量或变量:
let exclamationMark: Character = "!"
复制代码
字符串值能够经过将一个字符值数组做为参数传递给它的初始化器来构造:
let catCharacters: [Character] = ["C", "a", "t", "!", "🐱"]
let catString = String(catCharacters)
print(catString)
// Prints "Cat!🐱"
复制代码
可使用加法运算符(+)将字符串值相加(或链接),从而建立一个新的字符串值:
let string1 = "hello"
let string2 = " there"
var welcome = string1 + string2
// welcome now equals "hello there"
复制代码
您还可使用添加赋值操做符(+=)将字符串值追加到现有字符串变量:
var instruction = "look over"
instruction += string2
// instruction now equals "look over there"
复制代码
你可使用字符串类型的append()方法将一个字符值附加到一个字符串变量:
let exclamationMark: Character = "!"
welcome.append(exclamationMark)
// welcome now equals "hello there!"
复制代码
注意 不能将字符串或字符附加到现有的字符变量,由于字符值必须只包含单个字符。
若是使用多行字符串文原本构建较长的字符串的行,则但愿字符串中的每一行都以换行符结束,包括最后一行。例如:
let badStart = """ one two """
let end = """ three """
print(badStart + end)
// Prints two lines:
// one
// twothree
let goodStart = """ one two """
print(goodStart + end)
// Prints three lines:
// one
// two
// three
复制代码
在上面的代码中,将badStart与end链接会产生一个两行字符串,这不是预期的结果。由于badStart的最后一行没有以换行符结束,因此该行与end的第一行合并在一块儿。相反,goodStart的两行末尾都有一个换行符,因此当它与end合并时,结果如预期的同样有三行。
字符串插值是一种经过将常量、变量、文本和表达式的值包含在字符串文本中构造新字符串值的方法。能够在单行和多行字符串文本中使用字符串插值。你插入到字符串文字中的每一项都被包裹在一对括号中,加上一个反斜杠():
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)插入字符串文字中。当计算字符串插值以建立实际字符串时,将用乘数的实际值替换此占位符。
multiplier的值也是字符串后面较大表达式的一部分。这个表达式计算Double(乘法器)* 2.5的值,并将结果(7.5)插入到字符串中。在本例中,当表达式包含在字符串文字中时,它被写成(Double(multiplier) * 2.5)。
可使用扩展字符串分隔符建立包含字符的字符串,不然这些字符将被视为字符串插值。例如:
print(#"Write an interpolated string in Swift using \(multiplier)."#)
// Prints "Write an interpolated string in Swift using \(multiplier)."
复制代码
若要在使用扩展分隔符的字符串中使用字符串插值,请将反斜杠后的数字符号数与字符串开始和结束的数字符号数匹配。例如:
print(#"6 times 7 is \#(6 * 7)."#)
// Prints "6 times 7 is 42."
复制代码
注意 在内插字符串的括号内编写的表达式不能包含未转义的反斜杠()、回车符或换行符。可是,它们能够包含其余字符串文字。
Unicode是一种国际标准,用于在不一样的书写系统中编码、表示和处理文本。它使您可以以标准化的形式表示来自任何语言的几乎全部字符,而且可以从外部源(如文本文件或web页面)读写这些字符。Swift的字符串和字符类型彻底兼容unicode,如本节所述。
在后台,Swift的本地字符串类型是由Unicode标量值构建的。Unicode标量值是一个独特的21-bit数字字符或修饰符,如拉丁字母小写字母 A(“a”):U+0061 ,或前置小鸡(“🐥”):U+1F425。
注意,并非全部的21位Unicode标量值都被分配给字符—有些标量被保留以供未来分配或在UTF-16编码中使用。分配给字符的标量值一般也有一个名称,例如上面示例中的拉丁小写字母a和前面的CHICK。
Swift字符类型的每一个实例都表明一个扩展的字母簇。扩展的grapheme集群是由一个或多个Unicode标量组成的序列,(在组合时)生成一个可读的字符。
这是一个例子。字母e能够表示为单个Unicode标量é(带锐角的拉丁小写字母e,或U+00E9)。可是,同一个字母也能够表示为一对标量—标准字母e(拉丁小写字母e,或U+0065),后面是合并的重音标量(U+0301)。组合的重音标量以图形方式应用于它前面的标量,在支持unicode的文本呈现系统呈现时将e转换为é。
在这两种状况下,字母é都表示为一个Swift字符值,该值表示一个扩展的字母群。在第一种状况下,集群包含单个标量;在第二种状况下,它是两个标量的一个簇:
let eAcute: Character = "\u{E9}" // é
let combinedEAcute: Character = "\u{65}\u{301}" // e followed by ́
// eAcute is é, combinedEAcute is é
复制代码
扩展的grapheme集群是一种灵活的方式,能够将许多复杂的脚本字符表示为单个字符值。例如,韩语字母中的韩语音节能够表示为预先组成或分解的序列。这两种表示形式在Swift中均可以做为单个字符值:
let precomposed: Character = "\u{D55C}" // 한
let decomposed: Character = "\u{1112}\u{1161}\u{11AB}" // ᄒ, ᅡ, ᆫ
// precomposed is 한, decomposed is 한
复制代码
扩展的grapheme集群容许使用标量来封装标记(例如组合封装圆,或U+20DD),从而将其余Unicode标量封装为单个字符值的一部分:
let enclosedEAcute: Character = "\u{E9}\u{20DD}"
// enclosedEAcute is é⃝
复制代码
Unicode区域指示符号的标量能够成对组合成一个字符值,例如区域指示符号字母U (U+1F1FA)和区域指示符号字母S (U+1F1F8)的组合:
let regionalIndicatorForUS: Character = "\u{1F1FA}\u{1F1F8}"
// regionalIndicatorForUS is 🇺🇸
复制代码
要检索字符串中字符值的计数,请使用字符串的count属性:
let unusualMenagerie = "Koala 🐨, Snail 🐌, Penguin 🐧, Dromedary 🐪"
print("unusualMenagerie has \(unusualMenagerie.count) characters")
// Prints "unusualMenagerie has 40 characters"
复制代码
注意,Swift对字符值使用扩展的grapheme集群意味着字符串链接和修改可能并不老是影响字符串的字符数。
举个例子,若是你初始化一个新的字符串与四字咖啡馆,而后添加一个结合急性口音(U + 0301)结束的字符串,由此产生的字符串仍然有字符计数4 é第四个字符,不是e:
var word = "cafe"
print("the number of characters in \(word) is \(word.count)")
// Prints "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.count)")
// Prints "the number of characters in café is 4"
复制代码
注意 扩展的grapheme集群能够由多个Unicode标量组成。这意味着不一样的字符——以及相同字符的不一样表示形式——须要存储不一样数量的内存。正由于如此,Swift中的字符在字符串表示中占用的内存并不相同。所以,若是不遍历字符串以肯定扩展的grapheme集群边界,就没法计算字符串中的字符数。若是使用特别长的字符串值,请注意count属性必须遍历整个字符串中的Unicode标量,以肯定该字符串的字符。
count属性返回的字符数并不老是与包含相同字符的NSString的length属性相同。NSString的长度是基于字符串UTF-16表示中的16位代码单元的数量,而不是字符串中的Unicode扩展字符群的数量。
能够经过字符串的方法和属性或下标语法访问和修改字符串。
每一个字符串值都有一个关联的索引类型,String.index,对应于字符串中每一个Character的位置。
如上所述,不一样的字符须要存储不一样的内存,所以,为了肯定哪一个字符位于特定位置,必须从该字符串的开始或结束遍历每一个Unicode标量。因为这个缘由,Swift字符串不能被整数值索引。
使用startIndex属性访问字符串第一个字符的位置。endIndex属性是字符串中最后一个字符以后的位置。所以,endIndex属性不是字符串下标的有效参数
。若是字符串为空,startIndex和endIndex相等。 (注:注意标红的地方)
使用String的index(before:)和index(after:)方法访问给定索引以前和以后的索引。要访问离给定索引更远的索引,可使用index(_:offsetBy:)方法,而不是屡次调用其中一个方法。
可使用下标语法访问特定字符串索引处的字符。
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
复制代码
试图访问字符串范围以外的索引或字符串范围以外的索引中的字符将触发运行时错误。
greeting[greeting.endIndex] // Error
greeting.index(after: greeting.endIndex) // Error
复制代码
使用indices属性来访问字符串中单个字符的全部索引。
for index in greeting.indices {
print("\(greeting[index]) ", terminator: "")
}
// Prints "G u t e n T a g ! "
复制代码
注意 你能够在任何符合集合协议的类型上使用startIndex和endIndex属性以及index(before:), index(after:)和index(_:offsetBy:)方法。这包括字符串(如这里所示)以及数组、字典和Set等集合类型。
使用insert(_:at:)方法在指定索引处插入一个字符,使用insert(contentsOf:at:)方法在指定索引处插入另外一个字符串的内容。
var welcome = "hello"
welcome.insert("!", at: welcome.endIndex)
// welcome now equals "hello!"
welcome.insert(contentsOf: " there", at: welcome.index(before: welcome.endIndex))
// welcome now equals "hello there!"
复制代码
使用remove(at:)方法从字符串中删除指定索引处的单个字符;使用removeSubrange(_:)方法删除指定范围内的子字符串:
welcome.remove(at: welcome.index(before: welcome.endIndex))
// welcome now equals "hello there"
let range = welcome.index(welcome.endIndex, offsetBy: -6)..<welcome.endIndex
welcome.removeSubrange(range)
// welcome now equals "hello"
复制代码
注意 你能够在任何符合RangeReplaceableCollection协议的类型上使用insert(:at:)、insert(contentsOf:at:)、remove(at:)和removeSubrange(:)方法。这包括字符串(如这里所示)以及数组、字典和Set等集合类型。
当您从字符串中获取子字符串时——例如,使用下标或相似prefix(_:)的方法——结果是substring的实例,而不是其余字符串。Swift中的子字符串具备与字符串相同的大部分方法,这意味着您能够像处理字符串同样处理子字符串。可是,与字符串不一样的是,在对字符串执行操做时,子字符串的使用时间很短。当准备长时间存储结果时,能够将子字符串转换为String的实例。例如:
let greeting = "Hello, world!"
let index = greeting.firstIndex(of: ",") ?? greeting.endIndex
let beginning = greeting[..<index]
// beginning is "Hello"
// Convert the result to a String for long-term storage.
let newString = String(beginning)
复制代码
与字符串同样,每一个子字符串都有一个存储组成子字符串的字符的内存区域。字符串和子字符串之间的区别在于,做为性能优化,子字符串能够重用用于存储原始字符串的部份内存,或用于存储另外一个子字符串的部份内存。(字符串有相似的优化,但若是两个字符串共享内存,它们是相等的。)这种性能优化意味着,在修改字符串或子字符串以前,没必要为复制内存付出性能成本
。如上所述,子字符串不适合长期存储—由于它们重用原始字符串的存储,因此只要使用它的任何子字符串,就必须将整个原始字符串保存在内存中。
在上面的例子中,greeting是一个字符串,这意味着它有一个存储组成字符串的字符的内存区域。由于“开始”是“问候语”的一个子串,它重复了问候语所使用的记忆。相反,newString是一个字符串——当它从子字符串建立时,它有本身的存储空间。下图显示了这些关系:
注意 字符串和子字符串都符合
StringProtocol
协议,这意味着字符串操做函数接受StringProtocol值一般很方便。可使用字符串或子字符串值调用此类函数。
Swift提供了三种比较文本值的方法:字符串和字符相等、前缀相等和后缀相等。
字符串和字符是否相等用“equal to”操做符(==)和“not equal to”操做符(!=)检查,如比较操做符中所述:
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")
}
// Prints "These two strings are considered equal"
复制代码
若是两个字符串值(或两个字符值)的扩展grapheme集群在规范上是等效的,则认为它们是相等的。若是扩展的grapheme集群具备相同的语言意义和外观,那么它们在标准上是等价的,即便它们是由不一样的Unicode标量在幕后组成的。
例如,拉丁字母E加上锐音(U+00E9)在标准上等同于拉丁字母E (U+0065)后面加上锐音(U+0301)。这两种扩展的grapheme集群都是表示字符é的有效方式,所以它们在规范上被认为是等价的:
// "Voulez-vous un café?" using LATIN SMALL LETTER E WITH ACUTE
let eAcuteQuestion = "Voulez-vous un caf\u{E9}?"
// "Voulez-vous un café?" using 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")
}
// Prints "These two strings are considered equal"
复制代码
相反,拉丁大写字母A(U + 0041,或“A”),是用于英语,并不等同于斯拉夫字母大写字母A(U + 0410,或“А”),是俄语。这两个角色在视觉上很类似,但语言意义不一样:
let latinCapitalLetterA: Character = "\u{41}"
let cyrillicCapitalLetterA: Character = "\u{0410}"
if latinCapitalLetterA != cyrillicCapitalLetterA {
print("These two characters are not equivalent.")
}
// Prints "These two characters are not equivalent."
复制代码
注意 Swift中的字符串和字符比较对语言环境不敏感。
要检查一个字符串是否有特定的字符串前缀或后缀,能够调用该字符串的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(_:)方法和romeoAndJuliet数组来计算第一幕的场景数:
var act1SceneCount = 0
for scene in romeoAndJuliet {
if scene.hasPrefix("Act 1 ") {
act1SceneCount += 1
}
}
print("There are \(act1SceneCount) scenes in Act 1")
// Prints "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")
// Prints "6 mansion scenes; 2 cell scenes"
复制代码
注意 hasPrefix(:)和hasSuffix(:)方法在每一个字符串中的扩展grapheme集群之间逐字符执行标准等价性比较,如字符串和字符相等性中所述。
当将Unicode字符串写入文本文件或其余存储中时,该字符串中的Unicode标量将以几种Unicode定义的编码形式之一进行编码。每一个表单都将字符串编码为小块,称为代码单元。其中包括UTF-8编码形式(将字符串编码为8位代码单元)、UTF-16编码形式(将字符串编码为16位代码单元)和UTF-32编码形式(将字符串编码为32位代码单元)。
Swift提供了几种不一样的方式来访问字符串的Unicode表示。您可使用for-in语句遍历该字符串,以访问做为Unicode扩展字符群的单个字符值。这个过程在字符处理中有描述。
或者,访问其余三种符合unicode的表示形式之一的字符串值:
下面每个例子展现了一个不一样的表示下面的字符串,这是由人物的D, o, g,‼(双感叹号,或者Unicode标量U+203C),和🐶字符(狗脸,或者Unicode标量U+1F436):
let dogString = "Dog‼🐶"
复制代码
经过迭代字符串的utf8属性,能够访问字符串的UTF-8表示形式。此属性的类型为String。UTF8View,它是一个无符号8位(UInt8)值的集合,对应字符串UTF-8表示的每一个字节:
for codeUnit in dogString.utf8 {
print("\(codeUnit) ", terminator: "")
}
print("")
// Prints "68 111 103 226 128 188 240 159 144 182 "
复制代码
在上面的示例中,前三个十进制codeUnit值(6八、1十一、103)表示字符D、o和g,它们的UTF-8表示与它们的ASCII表示相同。接下来的三个十进制代码单元值(22六、12八、188)是双感叹号字符的三字节UTF-8表示形式。后四个codeUnit值(240、15九、14四、182)是狗脸字符的四字节UTF-8表示。
经过迭代字符串的utf16属性,能够访问字符串的UTF-16表示。此属性的类型为String。UTF16View是一个无符号16位(UInt16)值的集合,每一个值对应字符串UTF-16表示中的16位代码单元:
for codeUnit in dogString.utf16 {
print("\(codeUnit) ", terminator: "")
}
print("")
// Prints "68 111 103 8252 55357 56374 "
复制代码
一样,前三个codeUnit值(6八、1十一、103)表示字符D、o和g,它们的UTF-16代码单位与字符串的UTF-8表示中的值相同(由于这些Unicode标量表示ASCII字符)。
第四个codeUnit值(8252)是十六进制值203C的十进制等价物,203C表示双感叹号字符的Unicode标量U+203C。这个字符能够用UTF-16表示为单个代码单元。
第五个和第六个codeUnit值(55357和56374)是狗脸字符的UTF-16代理项对表示。这些值分别是U+D83D的高代理值(十进制值55357)和U+DC36的低代理值(十进制值56374)。
经过迭代字符串的unicodeScalars属性,能够访问字符串值的Unicode标量表示形式。此属性的类型是UnicodeScalarView,它是UnicodeScalar类型的值的集合。
每一个UnicodeScalar都有一个value属性,它返回标量的21位值,用UInt32值表示:
for scalar in dogString.unicodeScalars {
print("\(scalar.value) ", terminator: "")
}
print("")
// Prints "68 111 103 8252 128054 "
复制代码
前三个UnicodeScalar值(6八、1十一、103)的值属性再次表示字符D、o和g。
第四个codeUnit值(8252)也是十六进制值203C的十进制等价物,203C表示Unicode标量U+203C,表示双感叹号字符。
第五个也是最后一个UnicodeScalar的值属性128054是十六进制值1F436的十进制等价值,它表示用于DOG FACE字符的Unicode标量U+1F436。
除了查询它们的值属性,每一个UnicodeScalar值也能够用来构造一个新的字符串值,例如字符串插值:
for scalar in dogString.unicodeScalars {
print("\(scalar) ")
}
// D
// o
// g
// ‼
// 🐶
复制代码
这一章节讲的主要是字符串和字符相关的内容,包括字符串的初始化,多行字符串如何表示,字符串的可变性,字符串是值类型,如何使用字符,链接字符串和字符的方法,字符串差值的用法,Unicode,以及字符串的属性的用法。Swift上字符串的索引使用和OC上的仍是有很大差异的,在文章里也有相应的案例,你们最好本身敲代码操做一下,这样才能加深印象。好了,这一块内容也比较简单,已经掌握的朋友能够跳过去看下一章节。
最后,喜欢这篇文章的朋友能够给个star,以鼓励我更加积极地去作这件事,嘿嘿~