Swift5.4 语言指南(六) 字符和字符串
★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★
➤微信公众号:山青咏芝(shanqingyongzhi)
➤博客园地址:山青咏芝(https://www.cnblogs.com/strengthen/)
➤GitHub地址:https://github.com/strengthen/LeetCode
➤原文地址:https://www.cnblogs.com/strengthen/p/9720541.html
➤如果链接不是山青咏芝的博客园地址,则可能是爬取作者的文章。
➤原文已修改更新!强烈建议点击原文地址阅读!支持作者!支持原创!
★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★
甲串是一系列字符,如的或。Swift字符串由类型表示。可以通过多种方式来访问a的内容,包括作为值的集合。"hello, world"
"albatross"
String
String
Character
Swift的String
和Character
类型提供了一种快速,符合Unicode的方式来处理代码中的文本。字符串创建和操作的语法轻巧易读,具有类似于C的字符串文字语法。字符串连接非常简单+
,只需将两个字符串与运算符结合在一起,即可通过在常量或变量之间进行选择来管理字符串的可变性,像Swift中的其他任何值一样。您也可以在称为字符串插值的过程中使用字符串将常量,变量,文字和表达式插入较长的字符串中。这样可以轻松创建用于显示,存储和打印的自定义字符串值。
尽管语法简单,但是Swift的String
类型是一种快速,现代的字符串实现。每个字符串都由独立于编码的Unicode字符组成,并支持以各种Unicode表示形式访问这些字符。
笔记
Swift的String
类型与Foundation的NSString
类联系在一起。Foundation还扩展String
为暴露由定义的方法NSString
。这意味着,如果导入Foundation,则可以NSString
在String
不强制转换的情况下访问这些方法。
有关String
与Foundation和Cocoa一起使用的更多信息,请参见在String和NSString之间桥接。
字符串文字
您可以String
在代码中将预定义值作为字符串文字包括在内。字符串文字是由双引号("
)包围的字符序列。
使用字符串文字作为常量或变量的初始值:
- let someString = "Some string literal value"
请注意,Swift会String
为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其余所有行之前要忽略的空格。但是,如果您在行的开头加上除右引号之前的空格,则将其包括在内。
在上面的示例中,即使缩进了整个多行字符串文字,字符串中的第一行和最后一行也不以任何空格开头。中间的行比右引号有更多的缩进,因此它以该额外的四空格缩进开始。
字符串文字中的特殊字符
字符串文字可以包含以下特殊字符:
- 转义的特殊字符
\0
(空字符),\\
(反斜杠),\t
(水平制表符),\n
(换行符),\r
(回车),\"
(双引号)和\'
(单引号) - 任意的Unicode标值,写为
\u{
Ñ}
,其中Ñ是一个1-8位十六进制数(统一在讨论的Unicode下文)
下面的代码显示了这些特殊字符的四个示例。该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 \"\"\"
- """
扩展字符串定界符
您可以在扩展定界符中放置字符串文字,以在字符串中包含特殊字符,而无需调用其效果。您将字符串放在引号("
)内,并用数字符号(#
)括起来。例如,打印字符串文字将打印换行符转义序列(),而不是在两行之间打印字符串。#"Line 1\nLine 2"#
\n
如果您需要字符串文字中字符的特殊效果,请匹配转义字符(\
)后字符串中数字符号的数量。例如,如果您的字符串是,并且您想换行,则可以改用。同样,也打破了界限。#"Line 1\nLine 2"#
#"Line 1\#nLine 2"#
###"Line1\###nLine2"###
使用扩展定界符创建的字符串文字也可以是多行字符串文字。您可以使用扩展定界符将文本包含"""
在多行字符串中,从而覆盖以文字结尾的默认行为。例如:
- let threeMoreDoubleQuotationMarks = #"""
- Here are three more double quotes: """
- """#
初始化一个空字符串
要创建一个空String
值作为构建更长字符串的起点,请为变量分配一个空字符串文字,或者String
使用初始化语法初始化一个新实例:
- var emptyString = "" // empty string literal
- var anotherEmptyString = String() // initializer syntax
- // these two strings are both empty, and are equivalent to each other
String
通过检查其布尔isEmpty
属性来确定一个值是否为空:
- if emptyString.isEmpty {
- print("Nothing to see here")
- }
- // Prints "Nothing to see here"
字符串可变性
您String
可以通过将某个变量分配给变量(在这种情况下可以修改)或常量(在这种情况下不能修改)来指示是否可以修改(或mutated):
- 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中的字符串突变不同,在Objective-C和Cocoa中,您可以在两个类(NSString
和NSMutableString
)之间进行选择,以指示是否可以对字符串进行突变。
字符串是值类型
Swift的String
类型是一个值类型。如果创建一个新String
值,则将该String
值传递给函数或方法时,或将其分配给常量或变量时,将复制该值。在每种情况下,String
都会创建现有值的新副本,并传递或分配新副本,而不是原始版本。值类型在《结构和枚举是值类型》中进行了描述。
Swift的默认复制String
行为可确保当函数或方法为您传递值时,无论String
该String
值来自何处,您显然都拥有该确切值。您可以确信,除非您自己修改,否则不会修改传递的字符串。
在后台,Swift的编译器优化了字符串的用法,因此仅在绝对必要时才进行实际复制。这意味着在将字符串作为值类型使用时,始终可以获得出色的性能。
使用角色
您可以通过-循环遍历字符串来访问a的各个Character
值:String
for
in
- for character in "Dog!🐶" {
- print(character)
- }
- // D
- // o
- // g
- // !
- // 🐶
的for
-in
环中描述对于-在循环中。
另外,您可以Character
通过提供Character
类型注释从单字符字符串文字中创建独立的常量或变量:
- let exclamationMark: Character = "!"
String
可以通过将Character
值数组作为参数传递给其初始值设定项来构造值:
- let catCharacters: [Character] = ["C", "a", "t", "!", "🐱"]
- let catString = String(catCharacters)
- print(catString)
- // Prints "Cat!🐱"
连接字符串和字符
String
可以使用加法运算符()将值加在一起(或串联在一起+
)以创建新String
值:
- let string1 = "hello"
- let string2 = " there"
- var welcome = string1 + string2
- // welcome now equals "hello there"
您还可以使用附加赋值运算符()将String
值附加到现有String
变量中+=
:
- var instruction = "look over"
- instruction += string2
- // instruction now equals "look over there"
您可以使用类型的方法将Character
值附加到String
变量:String
append()
- let exclamationMark: Character = "!"
- welcome.append(exclamationMark)
- // welcome now equals "hello there!"
笔记
您不能将String
或附加Character
到现有Character
变量中,因为一个Character
值只能包含一个字符。
如果您使用多行字符串文字构造更长的字符串的行,则希望字符串中的每一行都以换行符结尾,包括最后一行。例如:
- 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
结果结合使用时,可以得到预期的三行。
字符串插值
字符串插值是通过String
将常量,变量,文字和表达式的值包含在字符串文字中来构造新值的一种方法。您可以在单行和多行字符串文字中使用字符串插值。您插入字符串文字中的每个项目都用一对括号括起来,并以反斜杠(\
)为前缀:
- 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
评估字符串插值以创建实际字符串时,该占位符将替换为的实际值。
的值multiplier
也是该字符串后面较大表达式的一部分。该表达式计算的值并将结果()插入字符串中。在这种情况下,表达式的编写方式是将其包含在字符串文字中。Double(multiplier) * 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是用于在不同书写系统中编码,表示和处理文本的国际标准。它使您能够以标准化的形式表示来自任何语言的几乎所有字符,并且可以与诸如文本文件或网页之类的外部源进行读写。如本节所述,Swift的String
和Character
类型完全兼容Unicode。
Unicode标量值
在幕后,Swift的本机String
类型是根据Unicode标量值构建的。一个Unicode标量值为字符或改性剂的唯一的21位数字,如U+0061
为(),或为()。LATIN SMALL LETTER A
"a"
U+1F425
FRONT-FACING BABY CHICK
"🐥"
请注意,并非所有21位Unicode标量值都分配给一个字符-一些标量保留用于将来分配或用于UTF-16编码。通常,已分配给字符的标量值也具有名称,例如上述示例中的和。LATIN SMALL LETTER A
FRONT-FACING BABY CHICK
扩展字素簇
SwiftCharacter
类型的每个实例都代表一个扩展的字素簇。扩展字素簇是一个或多个Unicode标量的序列,这些标量(组合时)产生一个人类可读的字符。
这是一个例子。该字母é
可以表示为单个Unicode标量é
(或)。但是,同一字母也可以表示为一对标量-标准字母(或),后跟标量()。该标以图形应用于标量它之前,把一个成一个,当它是由一个支持Unicode的文本渲染系统渲染。LATIN SMALL LETTER E WITH ACUTE
U+00E9
e
LATIN SMALL LETTER E
U+0065
COMBINING ACUTE ACCENT
U+0301
COMBINING ACUTE ACCENT
e
é
在这两种情况下,字母é
均表示为单个SwiftCharacter
值,该值表示扩展的字素簇。在第一种情况下,集群包含单个标量。在第二种情况下,它是两个标量的集群:
- let eAcute: Character = "\u{E9}" // é
- let combinedEAcute: Character = "\u{65}\u{301}" // e followed by ́
- // eAcute is é, combinedEAcute is é
扩展字素簇是一种将多个复杂脚本字符表示为单个Character
值的灵活方式。例如,韩文字母的韩文音节可以表示为预组合或分解序列。这两种表示形式都可以Character
在Swift中作为单个值使用:
- let precomposed: Character = "\u{D55C}" // 한
- let decomposed: Character = "\u{1112}\u{1161}\u{11AB}" // ᄒ, ᅡ, ᆫ
- // precomposed is 한, decomposed is 한
扩展的字素簇使标量可以包含标记(例如,或),以将其他Unicode标量作为单个值的一部分包含在内:COMBINING ENCLOSING CIRCLE
U+20DD
Character
- let enclosedEAcute: Character = "\u{E9}\u{20DD}"
- // enclosedEAcute is é⃝
区域指示符符号的Unicode标量可以成对组合以形成单个Character
值,例如()和()的组合:REGIONAL INDICATOR SYMBOL LETTER U
U+1F1FA
REGIONAL INDICATOR SYMBOL LETTER S
U+1F1F8
- let regionalIndicatorForUS: Character = "\u{1F1FA}\u{1F1F8}"
- // regionalIndicatorForUS is 🇺🇸
计数字符
要检索Character
字符串中值的计数,请使用字符串的count
属性:
- let unusualMenagerie = "Koala 🐨, Snail 🐌, Penguin 🐧, Dromedary 🐪"
- print("unusualMenagerie has \(unusualMenagerie.count) characters")
- // Prints "unusualMenagerie has 40 characters"
请注意,Swift使用扩展的字素簇来获取Character
值意味着字符串的串联和修改可能并不总是会影响字符串的字符数。
例如,如果您使用4个字符的单词初始化一个新字符串cafe
,然后在该字符串的末尾添加(),则所得字符串仍将具有一个字符计数为,第四个字符为,而不是:COMBINING ACUTE ACCENT
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"
笔记
扩展字素簇可以由多个Unicode标量组成。这意味着不同的字符(以及相同字符的不同表示形式)可能需要存储不同数量的内存。因此,在字符串表示中,Swift中的字符不会占用相同的内存量。结果,如果不对字符串进行迭代来确定其扩展的字形簇边界,就无法计算字符串中的字符数。如果要使用特别长的字符串值,请注意,该count
属性必须在整个字符串中的Unicode标量上进行迭代,才能确定该字符串的字符。
该count
属性返回的字符数并不总是与包含相同字符的的length
属性NSString
相同。an的长度NSString
基于字符串的UTF-16表示形式中16位代码单元的数量,而不是字符串中的Unicode扩展字素簇的数量。
访问和修改字符串
您可以通过字符串的方法和属性或使用下标语法来访问和修改字符串。
字符串索引
每个String
值都有一个关联的索引类型,String.Index
它对应于每个值Character
在字符串中的位置。
如上所述,不同的字符可能需要存储不同数量的内存,因此,为了确定哪个Character
字符位于特定位置,您必须从该Unicode标量的开头或结尾开始对其进行迭代String
。因此,Swift字符串不能用整数值索引。
使用该startIndex
属性访问的第Character
一个的位置String
。该endIndex
属性是String
。中最后一个字符之后的位置。结果,该endIndex
属性不是字符串下标的有效参数。如果String
是空的,startIndex
并且endIndex
是相等的。
您可以使用的index(before:)
和index(after:)
方法访问给定索引之前和之后的索引String
。若要访问距离给定索引更远的索引,可以使用index(_:offsetBy:)
方法而不是多次调用这些方法之一。
您可以使用下标语法来访问Character
特定String
索引处的。
- 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: 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:)
符合的任何类型的方法Collection
的协议。这包括String
,如下图所示,以及集合类型,如Array
,Dictionary
和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"
笔记
您可以使用insert(_:at:)
,insert(contentsOf:at:)
,remove(at:)
,和removeSubrange(_:)
在任何类型的方法符合该RangeReplaceableCollection
协议。这包括String
,如下图所示,以及集合类型,如Array
,Dictionary
和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
是一个字符串,这意味着它具有一个存储区域,用于存储组成该字符串的字符。因为beginning
是的子字符串greeting
,所以它重用了所greeting
使用的内存。相反,newString
是一个字符串-从子字符串创建它时,它具有自己的存储空间。下图显示了这些关系:
笔记
二者String
并Substring
符合StringProtocol
协议,这意味着它的常方便的字符串操作函数接受StringProtocol
的值。您可以使用aString
或Substring
value调用此类函数。
比较字符串
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")
- }
- // Prints "These two strings are considered equal"
如果两个String
值(或两个Character
值)的扩展字素簇规范相等,则认为它们相等。如果扩展字素簇具有相同的语言含义和外观,则它们在规范上是等价的,即使它们是由幕后的不同Unicode标量组成的。
例如,()通常等于()后跟()。这两个扩展的字素簇都是表示character的有效方法,因此它们被认为是正当的:LATIN SMALL LETTER E WITH ACUTE
U+00E9
LATIN SMALL LETTER E
U+0065
COMBINING ACUTE ACCENT
U+0301
é
- // "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"
相反,(或),如英语中使用的,是不是等同于(或),在俄罗斯使用。这些字符在视觉上相似,但是在语言上没有相同的含义:LATIN CAPITAL LETTER A
U+0041
"A"
CYRILLIC CAPITAL LETTER A
U+0410
"А"
- let latinCapitalLetterA: Character = "\u{41}"
- let cyrillicCapitalLetterA: Character = "\u{0410}"
- if latinCapitalLetterA != cyrillicCapitalLetterA {
- print("These two characters aren't equivalent.")
- }
- // Prints "These two characters aren't 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(_:)
方法计算Capulet的宅邸和Friar Lawrence的单元中或周围发生的场景数量:
- 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(_:)
在每一个串的方法执行所述扩展字形簇之间的字符逐字符规范等价比较,如在所述的字符串和字符平等。
字符串的Unicode表示形式
将Unicode字符串写入文本文件或其他存储时,该字符串中的Unicode标量将以几种Unicode定义的编码形式之一进行编码。每种形式都以称为代码单元的小块对字符串进行编码。这些格式包括UTF-8编码形式(将字符串编码为8位代码单元),UTF-16编码形式(将字符串编码为16位代码单元)和UTF-32编码形式(编码以32位代码为单位的字符串)。
Swift提供了几种不同的方式来访问字符串的Unicode表示形式。您可以使用for
-in
语句遍历字符串,以Character
Unicode扩展字素簇的形式访问其各个值。使用字符中描述了此过程。
或者,以String
其他三个符合Unicode的表示形式之一访问值:
- UTF-8代码单元的集合(通过字符串的
utf8
属性访问) - UTF-16代码单元的集合(通过字符串的
utf16
属性访问) - 相当于字符串的UTF-32编码形式的21位Unicode标量值的集合(通过字符串的
unicodeScalars
属性访问)
下面示出了每个实施例下面的字符串,它是由所述字符的向上的不同表示D
,o
,g
,‼
(或Unicode标),以及🐶字符(或Unicode标):DOUBLE EXCLAMATION MARK
U+203C
DOG FACE
U+1F436
- let dogString = "Dog‼🐶"
UTF-8表示形式
您可以String
通过对其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
值(68
,111
,103
)所表示的字符D
,o
和g
,其UTF-8表示相同的ASCII表示。接下来的三个十进制codeUnit
值(226
,128
,188
)是一个三字节UTF-8表示的字符。最后四个值(,,,)是一个四字节UTF-8表示的字符。DOUBLE EXCLAMATION MARK
codeUnit
240
159
144
182
DOG FACE
UTF-16表示形式
您可以String
通过对其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
值(68
,111
,103
)所表示的字符D
,o
和g
,其UTF-16代码单元具有相同的值作为字符串的UTF-8表示(因为这些Unicode标量表示ASCII字符)。
第四codeUnit
值(8252
)是一个十进位等值的十六进制值的203C
,它代表了Unicode标U+203C
为字符。该字符可以表示为UTF-16中的单个代码单元。DOUBLE EXCLAMATION MARK
第五和第六个codeUnit
值(55357
和56374
)是字符的UTF-16代理对表示。这些值的高代理值(十进制值)和一个低代理值(十进制值)。DOG FACE
U+D83D
55357
U+DC36
56374
Unicode标量表示
您可以String
通过迭代其unicodeScalars
属性来访问值的Unicode标量表示形式。此属性是type UnicodeScalarView
,它是type值的集合UnicodeScalar
。
每个属性UnicodeScalar
都有一个value
返回标量的21位值的属性,用一个UInt32
值表示:
- for scalar in dogString.unicodeScalars {
- print("\(scalar.value) ", terminator: "")
- }
- print("")
- // Prints "68 111 103 8252 128054 "
的value
前三个属性UnicodeScalar
值(68
,111
,103
)再次表示字符D
,o
和g
。
第四codeUnit
值(8252
)又是一个十进位等值的十六进制值的203C
,它代表了Unicode标U+203C
为字符。DOUBLE EXCLAMATION MARK
在value
第五和最后的属性UnicodeScalar
,128054
是一个十进制等效的十六进制值的1F436
,它代表了Unicode标U+1F436
为字符。DOG FACE
作为查询其value
属性的替代方法,每个UnicodeScalar
值也可以用于构造新String
值,例如使用字符串插值:
- for scalar in dogString.unicodeScalars {
- print("\(scalar) ")
- }
- // D
- // o
- // g
- // ‼
- // 🐶