为有牺牲多壮志,敢教日月换新天。

Swift5.4 语言指南(六) 字符和字符串

★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★
➤微信公众号:山青咏芝(shanqingyongzhi)
➤博客园地址:山青咏芝(https://www.cnblogs.com/strengthen/
➤GitHub地址:https://github.com/strengthen/LeetCode
➤原文地址:https://www.cnblogs.com/strengthen/p/9720541.html 
➤如果链接不是山青咏芝的博客园地址,则可能是爬取作者的文章。
➤原文已修改更新!强烈建议点击原文地址阅读!支持作者!支持原创!
★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★

热烈欢迎,请直接点击!!!

进入博主App Store主页,下载使用各个作品!!!

注:博主将坚持每月上线一个新app!!!

是一系列字符,如的Swift字符串由类型表示可以通过多种方式来访问a的内容,包括作为的集合"hello, world""albatross"StringStringCharacter

Swift的StringCharacter类型提供了一种快速,符合Unicode的方式来处理代码中的文本。字符串创建和操作的语法轻巧易读,具有类似于C的字符串文字语法。字符串连接非常简单+,只需将两个字符串与运算符结合在一起,即可通过在常量或变量之间进行选择来管理字符串的可变性,像Swift中的其他任何值一样。您也可以在称为字符串插值的过程中使用字符串将常量,变量,文字和表达式插入较长的字符串中。这样可以轻松创建用于显示,存储和打印的自定义字符串值。

尽管语法简单,但是Swift的String类型是一种快速,现代的字符串实现。每个字符串都由独立于编码的Unicode字符组成,并支持以各种Unicode表示形式访问这些字符。

笔记

Swift的String类型与Foundation的NSString类联系在一起Foundation还扩展String为暴露由定义的方法NSString这意味着,如果导入Foundation,则可以NSStringString不强制转换的情况下访问这些方法

有关String与Foundation和Cocoa一起使用的更多信息,请参见在String和NSString之间桥接

字符串文字

您可以String在代码中将预定义值作为字符串文字包括在内字符串文字是由双引号("包围的字符序列

使用字符串文字作为常量或变量的初始值:

  1. let someString = "Some string literal value"

请注意,Swift会StringsomeString常量推断类型,因为它是使用字符串文字值初始化的。

多行字符串文字

如果您需要一个跨越多行的字符串,请使用多行字符串文字-一种由三个双引号引起来的字符序列:

  1. let quotation = """
  2. The White Rabbit put on his spectacles. "Where shall I begin,
  3. please your Majesty?" he asked.
  4. "Begin at the beginning," the King said gravely, "and go on
  5. till you come to the end; then stop."
  6. """

多行字符串文字包括其右引号和右引号之间的所有行。字符串从左引号("""之后的第一行开始,并在右引号之前的行结束,这意味着下面的字符串都不以换行符开头或结尾:

  1. let singleLineString = "These are the same."
  2. let multilineString = """
  3. These are the same.
  4. """

当您的源代码在多行字符串文字中包含一个换行符时,该换行符也会出现在字符串的值中。如果要使用换行符使源代码更易于阅读,但又不想使换行符成为字符串值的一部分,请在\这些行的末尾写一个反斜杠():

  1. let softWrappedQuotation = """
  2. The White Rabbit put on his spectacles. "Where shall I begin, \
  3. please your Majesty?" he asked.
  4. "Begin at the beginning," the King said gravely, "and go on \
  5. till you come to the end; then stop."
  6. """

要制作以换行开头或结尾的多行字符串文字,请将空白行写为第一行或最后一行。例如:

  1. let lineBreaks = """
  2. This string starts with a line break.
  3. It also ends with a line break.
  4. """

可以缩进多行字符串以匹配周围的代码。右引号("""之前的空格告诉Swift其余所有行之前要忽略的空格。但是,如果您在行的开头加上除右引号之前的空格,则将包括在内。

../_images/multilineStringWhitespace_2x.png

在上面的示例中,即使缩进了整个多行字符串文字,字符串中的第一行和最后一行也不以任何空格开头。中间的行比右引号有更多的缩进,因此它以该额外的四空格缩进开始。

字符串文字中的特殊字符

字符串文字可以包含以下特殊字符:

  • 转义的特殊字符\0(空字符),\\(反斜杠),\t(水平制表符),\n(换行符),\r(回车),\"(双引号)和\'(单引号)
  • 任意的Unicode标值,写为\u{Ñ},其中Ñ是一个1-8位十六进制数(统一在讨论的Unicode下文)

下面的代码显示了这些特殊字符的四个示例。wiseWords常量包含两个转义的双引号。dollarSignblackHeartsparklingHeart常量展示Unicode标格式:

  1. let wiseWords = "\"Imagination is more important than knowledge\" - Einstein"
  2. // "Imagination is more important than knowledge" - Einstein
  3. let dollarSign = "\u{24}" // $, Unicode scalar U+0024
  4. let blackHeart = "\u{2665}" // ♥, Unicode scalar U+2665
  5. let sparklingHeart = "\u{1F496}" // 💖, Unicode scalar U+1F496

由于多行字符串文字使用三个双引号而不是一个引号引起来,因此您可以"在多行字符串文字中包含一个双引号(),而不必对其进行转义。要将文本包含"""在多行字符串中,请至少使用引号引起来。例如:

  1. let threeDoubleQuotationMarks = """
  2. Escaping the first quotation mark \"""
  3. Escaping all three quotation marks \"\"\"
  4. """

扩展字符串定界符

您可以在扩展定界符中放置字符串文字,以在字符串中包含特殊字符,而无需调用其效果。您将字符串放在引号(")内,并用数字符号(#括起来例如,打印字符串文字将打印换行符转义序列(),而不是在两行之间打印字符串。#"Line 1\nLine 2"#\n

如果您需要字符串文字中字符的特殊效果,请匹配转义字符(\)后字符串中数字符号的数量例如,如果您的字符串是,并且您想换行,则可以改用。同样,也打破了界限。#"Line 1\nLine 2"##"Line 1\#nLine 2"####"Line1\###nLine2"###

使用扩展定界符创建的字符串文字也可以是多行字符串文字。您可以使用扩展定界符将文本包含"""在多行字符串中,从而覆盖以文字结尾的默认行为。例如:

  1. let threeMoreDoubleQuotationMarks = #"""
  2. Here are three more double quotes: """
  3. """#

初始化一个空字符串

要创建一个空String值作为构建更长字符串的起点,请为变量分配一个空字符串文字,或者String使用初始化语法初始化一个新实例:

  1. var emptyString = "" // empty string literal
  2. var anotherEmptyString = String() // initializer syntax
  3. // these two strings are both empty, and are equivalent to each other

String通过检查其布尔isEmpty属性来确定一个是否为空

  1. if emptyString.isEmpty {
  2. print("Nothing to see here")
  3. }
  4. // Prints "Nothing to see here"

字符串可变性

String可以通过将某个变量分配给变量(在这种情况下可以修改)或常量(在这种情况下不能修改)来指示是否可以修改(或mutated):

  1. var variableString = "Horse"
  2. variableString += " and carriage"
  3. // variableString is now "Horse and carriage"
  4. let constantString = "Highlander"
  5. constantString += " and another Highlander"
  6. // this reports a compile-time error - a constant string cannot be modified

笔记

此方法与Objective-C和Cocoa中的字符串突变不同,在Objective-C和Cocoa中,您可以在两个类(NSStringNSMutableString之间进行选择,以指示是否可以对字符串进行突变。

字符串是值类型

Swift的String类型是一个值类型如果创建一个新String值,则将该String传递给函数或方法时,或将其分配给常量或变量时,将复制在每种情况下,String都会创建现有值的新副本,并传递或分配新副本,而不是原始版本。值类型在《结构和枚举是值类型》中进行了描述

Swift的默认复制String行为可确保当函数或方法为您传递值时,无论StringString值来自何处,您显然都拥有该确切值。您可以确信,除非您自己修改,否则不会修改传递的字符串。

在后台,Swift的编译器优化了字符串的用法,因此仅在绝对必要时才进行实际复制。这意味着在将字符串作为值类型使用时,始终可以获得出色的性能。

使用角色

您可以通过-循环遍历字符串来访问a的各个CharacterStringforin

  1. for character in "Dog!🐶" {
  2. print(character)
  3. }
  4. // D
  5. // o
  6. // g
  7. // !
  8. // 🐶

for-in环中描述对于-在循环中

另外,您可以Character通过提供Character类型注释从单字符字符串文字中创建独立的常量或变量

  1. let exclamationMark: Character = "!"

String可以通过将Character数组作为参数传递给其初始值设定项来构造值:

  1. let catCharacters: [Character] = ["C", "a", "t", "!", "🐱"]
  2. let catString = String(catCharacters)
  3. print(catString)
  4. // Prints "Cat!🐱"

连接字符串和字符

String可以使用加法运算符()将值加在一起(或串联在一起+)以创建新String值:

  1. let string1 = "hello"
  2. let string2 = " there"
  3. var welcome = string1 + string2
  4. // welcome now equals "hello there"

您还可以使用附加赋值运算符(String附加到现有String变量中+=

  1. var instruction = "look over"
  2. instruction += string2
  3. // instruction now equals "look over there"

您可以使用类型的方法Character附加String变量Stringappend()

  1. let exclamationMark: Character = "!"
  2. welcome.append(exclamationMark)
  3. // welcome now equals "hello there!"

笔记

您不能将String附加Character到现有Character变量中,因为一个Character值只能包含一个字符。

如果您使用多行字符串文字构造更长的字符串的行,则希望字符串中的每一行都以换行符结尾,包括最后一行。例如:

  1. let badStart = """
  2. one
  3. two
  4. """
  5. let end = """
  6. three
  7. """
  8. print(badStart + end)
  9. // Prints two lines:
  10. // one
  11. // twothree
  12. let goodStart = """
  13. one
  14. two
  15. """
  16. print(goodStart + end)
  17. // Prints three lines:
  18. // one
  19. // two
  20. // three

在上面的代码中,badStart串联end会产生两行字符串,这不是理想的结果。由于的最后一行badStart不以换行符结尾,因此该行与的第一行合并end相比之下,两行都goodStart以换行符结尾,因此将其与end结果结合使用时,可以得到预期的三行。

字符串插值

字符串插值是通过String将常量,变量,文字和表达式的值包含在字符串文字中来构造新值的一种方法您可以在单行和多行字符串文字中使用字符串插值。您插入字符串文字中的每个项目都用一对括号括起来,并以反斜杠(\为前缀

  1. let multiplier = 3
  2. let message = "\(multiplier) times 2.5 is \(Double(multiplier) * 2.5)"
  3. // message is "3 times 2.5 is 7.5"

在上面的示例中,将的值multiplier插入到字符串文字中,如\(multiplier)multiplier评估字符串插值以创建实际字符串时,该占位符将替换为的实际值

的值multiplier也是该字符串后面较大表达式的一部分。该表达式计算的值并将结果()插入字符串中。在这种情况下,表达式的编写方式是将其包含在字符串文字中。Double(multiplier) 2.57.5\(Double(multiplier) 2.5)

您可以使用扩展的字符串定界符来创建包含字符的字符串,否则这些字符将被视为字符串插值。例如:

  1. print(#"Write an interpolated string in Swift using \(multiplier)."#)
  2. // Prints "Write an interpolated string in Swift using \(multiplier)."

要在使用扩展定界符的字符串中使用字符串插值,请将反斜杠后的数字符号数与字符串开头和结尾处的数字符号数匹配。例如:

  1. print(#"6 times 7 is \#(6 * 7)."#)
  2. // Prints "6 times 7 is 42."

笔记

您在插值字符串的括号内编写的表达式不能包含未转义的反斜杠(\),回车符或换行符。但是,它们可以包含其他字符串文字。

统一码

Unicode是用于在不同书写系统中编码,表示和处理文本的国际标准。它使您能够以标准化的形式表示来自任何语言的几乎所有字符,并且可以与诸如文本文件或网页之类的外部源进行读写。如本节所述,Swift的StringCharacter类型完全兼容Unicode。

Unicode标量值

在幕后,Swift的本机String类型是根据Unicode标量值构建的一个Unicode标量值为字符或改性剂的唯一的21位数字,如U+0061),或)。LATIN SMALL LETTER A"a"U+1F425FRONT-FACING BABY CHICK"🐥"

请注意,并非所有21位Unicode标量值都分配给一个字符-一些标量保留用于将来分配或用于UTF-16编码。通常,已分配给字符的标量值也具有名称,例如上述示例中的LATIN SMALL LETTER AFRONT-FACING BABY CHICK

扩展字素簇

SwiftCharacter类型的每个实例都代表一个扩展的字素簇扩展字素簇是一个或多个Unicode标量的序列,这些标量(组合时)产生一个人类可读的字符。

这是一个例子。该字母é可以表示为单个Unicode标量é)。但是,同一字母也可以表示为一标量-标准字母),后跟标量()。标以图形应用于标量它之前,把一个成一个,当它是由一个支持Unicode的文本渲染系统渲染。LATIN SMALL LETTER WITH ACUTEU+00E9eLATIN SMALL LETTER EU+0065COMBINING ACUTE ACCENTU+0301COMBINING ACUTE ACCENTeé

在这两种情况下,字母é均表示为单个SwiftCharacter值,该值表示扩展的字素簇。在第一种情况下,集群包含单个标量。在第二种情况下,它是两个标量的集群:

  1. let eAcute: Character = "\u{E9}" // é
  2. let combinedEAcute: Character = "\u{65}\u{301}" // e followed by ́
  3. // eAcute is é, combinedEAcute is é

扩展字素簇是一种将多个复杂脚本字符表示为单个Character的灵活方式例如,韩文字母的韩文音节可以表示为预组合或分解序列。这两种表示形式都可以Character在Swift中作为单个值使用:

  1. let precomposed: Character = "\u{D55C}" // 한
  2. let decomposed: Character = "\u{1112}\u{1161}\u{11AB}" // ᄒ, ᅡ, ᆫ
  3. // precomposed is 한, decomposed is 한

扩展的字素簇使标量可以包含标记(例如,或),以将其他Unicode标量作为单个值的一部分包含在内COMBINING ENCLOSING CIRCLEU+20DDCharacter

  1. let enclosedEAcute: Character = "\u{E9}\u{20DD}"
  2. // enclosedEAcute is é⃝

区域指示符符号的Unicode标量可以成对组合以形成单个Character值,例如)和)的组合REGIONAL INDICATOR SYMBOL LETTER UU+1F1FAREGIONAL INDICATOR SYMBOL LETTER SU+1F1F8

  1. let regionalIndicatorForUS: Character = "\u{1F1FA}\u{1F1F8}"
  2. // regionalIndicatorForUS is 🇺🇸

计数字符

要检索Character字符串中值的计数,请使用字符串的count属性:

  1. let unusualMenagerie = "Koala 🐨, Snail 🐌, Penguin 🐧, Dromedary 🐪"
  2. print("unusualMenagerie has \(unusualMenagerie.count) characters")
  3. // Prints "unusualMenagerie has 40 characters"

请注意,Swift使用扩展的字素簇来获取Character值意味着字符串的串联和修改可能并不总是会影响字符串的字符数。

例如,如果您使用4个字符的单词初始化一个新字符串cafe,然后在该字符串的末尾添加),则所得字符串仍将具有一个字符计数为,第四个字符为,而不是COMBINING ACUTE ACCENTU+03014e

  1. var word = "cafe"
  2. print("the number of characters in \(word) is \(word.count)")
  3. // Prints "the number of characters in cafe is 4"
  4. word += "\u{301}" // COMBINING ACUTE ACCENT, U+0301
  5. print("the number of characters in \(word) is \(word.count)")
  6. // 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一个的位置StringendIndex属性是String。中最后一个字符之后的位置结果,该endIndex属性不是字符串下标的有效参数。如果String是空的,startIndex并且endIndex是相等的。

您可以使用的index(before:)index(after:)方法访问给定索引之前和之后的索引String若要访问距离给定索引更远的索引,可以使用index(_:offsetBy:)方法而不是多次调用这些方法之一。

您可以使用下标语法来访问Character特定String索引处的。

  1. let greeting = "Guten Tag!"
  2. greeting[greeting.startIndex]
  3. // G
  4. greeting[greeting.index(before: greeting.endIndex)]
  5. // !
  6. greeting[greeting.index(after: greeting.startIndex)]
  7. // u
  8. let index = greeting.index(greeting.startIndex, offsetBy: 7)
  9. greeting[index]
  10. // a

尝试访问超出字符串范围Character的索引或超出字符串范围的索引将触发运行时错误。

  1. greeting[greeting.endIndex] // Error
  2. greeting.index(after: greeting.endIndex) // Error

使用该indices属性可访问字符串中各个字符的所有索引。

  1. for index in greeting.indices {
  2. print("\(greeting[index]) ", terminator: "")
  3. }
  4. // Prints "G u t e n T a g ! "

笔记

您可以使用startIndexendIndex属性和index(before:)index(after:)以及index(_:offsetBy:)符合的任何类型的方法Collection的协议。这包括String,如下图所示,以及集合类型,如ArrayDictionarySet

插入和移除

要将单个字符插入指定索引处的字符串中,请使用insert(_:at:)方法,并将另一个字符串的内容插入指定索引处,请使用insert(contentsOf:at:)方法。

  1. var welcome = "hello"
  2. welcome.insert("!", at: welcome.endIndex)
  3. // welcome now equals "hello!"
  4. welcome.insert(contentsOf: " there", at: welcome.index(before: welcome.endIndex))
  5. // welcome now equals "hello there!"

要从指定索引处的字符串中删除单个字符,请使用remove(at:)方法,而要在指定范围内删除子字符串,请使用removeSubrange(_:)方法:

  1. welcome.remove(at: welcome.index(before: welcome.endIndex))
  2. // welcome now equals "hello there"
  3. let range = welcome.index(welcome.endIndex, offsetBy: -6)..<welcome.endIndex
  4. welcome.removeSubrange(range)
  5. // welcome now equals "hello"

笔记

您可以使用insert(_:at:)insert(contentsOf:at:)remove(at:),和removeSubrange(_:)在任何类型的方法符合该RangeReplaceableCollection协议。这包括String,如下图所示,以及集合类型,如ArrayDictionarySet

子串

当从字符串中获取子字符串时(例如,使用下标或类似prefix(_:)方法),结果是的实例Substring,而不是另一个字符串。Swift中的子字符串与字符串具有大多数相同的方法,这意味着您可以像处理字符串一样使用子字符串。但是,与字符串不同,在对字符串执行操作时,只能在短时间内使用子字符串。当您准备将结果存储更长的时间时,可以将子字符串转换为的实例String例如:

  1. let greeting = "Hello, world!"
  2. let index = greeting.firstIndex(of: ",") ?? greeting.endIndex
  3. let beginning = greeting[..<index]
  4. // beginning is "Hello"
  5. // Convert the result to a String for long-term storage.
  6. let newString = String(beginning)

像字符串一样,每个子字符串都有一个存储区域,用于存储组成子字符串的字符。字符串和子字符串之间的区别在于,作为性能优化,子字符串可以重用用于存储原始字符串的部分内存,或用于存储另一个子字符串的部分内存。(字符串具有类似的优化,但是如果两个字符串共享内存,则它们是相等的。)这种性能优化意味着您无需支付复制内存的性能成本,直到您修改了字符串或子字符串。如上所述,子字符串不适合长期存储,因为它们会重复使用原始字符串的存储,因此,只要使用了任何子字符串,整个原始字符串都必须保留在内存中。

在上面的示例中,greeting是一个字符串,这意味着它具有一个存储区域,用于存储组成该字符串的字符。因为beginning是的子字符串greeting,所以它重用了所greeting使用的内存相反,newString是一个字符串-从子字符串创建它时,它具有自己的存储空间。下图显示了这些关系:

../_images/stringSubstring_2x.png

笔记

二者StringSubstring符合StringProtocol协议,这意味着它的常方便的字符串操作函数接受StringProtocol的值。您可以使用aStringSubstringvalue调用此类函数

比较字符串

Swift提供了三种比较文本值的方法:字符串和字符相等,前缀相等和后缀相等。

字符串和字符相等

字符串和字符平等检查与“等于”运算符(==)和“不等于”运算符(!=),如在比较操作符

  1. let quotation = "We're a lot alike, you and I."
  2. let sameQuotation = "We're a lot alike, you and I."
  3. if quotation == sameQuotation {
  4. print("These two strings are considered equal")
  5. }
  6. // Prints "These two strings are considered equal"

如果两个String值(或两个Character值)的扩展字素簇规范相等,则认为它们相等如果扩展字素簇具有相同的语言含义和外观,则它们在规范上是等价的,即使它们是由幕后的不同Unicode标量组成的。

例如,)通常等于)后跟)。这两个扩展的字素簇都是表示character的有效方法,因此它们被认为是正当的LATIN SMALL LETTER WITH ACUTEU+00E9LATIN SMALL LETTER EU+0065COMBINING ACUTE ACCENTU+0301é

  1. // "Voulez-vous un café?" using LATIN SMALL LETTER E WITH ACUTE
  2. let eAcuteQuestion = "Voulez-vous un caf\u{E9}?"
  3. // "Voulez-vous un café?" using LATIN SMALL LETTER E and COMBINING ACUTE ACCENT
  4. let combinedEAcuteQuestion = "Voulez-vous un caf\u{65}\u{301}?"
  5. if eAcuteQuestion == combinedEAcuteQuestion {
  6. print("These two strings are considered equal")
  7. }
  8. // Prints "These two strings are considered equal"

相反,),如英语中使用的,是不是等同于),在俄罗斯使用。这些字符在视觉上相似,但是在语言上没有相同的含义:LATIN CAPITAL LETTER AU+0041"A"CYRILLIC CAPITAL LETTER AU+0410"А"

  1. let latinCapitalLetterA: Character = "\u{41}"
  2. let cyrillicCapitalLetterA: Character = "\u{0410}"
  3. if latinCapitalLetterA != cyrillicCapitalLetterA {
  4. print("These two characters aren't equivalent.")
  5. }
  6. // Prints "These two characters aren't equivalent."

笔记

Swift中的字符串和字符比较对语言环境不敏感。

前缀和后缀相等

要检查字符串是否具有特定的字符串前缀或后缀,请调用字符串的hasPrefix(_:)hasSuffix(_:)方法,这两个方法都使用一个类型的单个参数String并返回布尔值。

以下示例考虑了一个字符串数组,这些字符串表示莎士比亚的《罗密欧与朱丽叶》的前两个动作的场景位置

  1. let romeoAndJuliet = [
  2. "Act 1 Scene 1: Verona, A public place",
  3. "Act 1 Scene 2: Capulet's mansion",
  4. "Act 1 Scene 3: A room in Capulet's mansion",
  5. "Act 1 Scene 4: A street outside Capulet's mansion",
  6. "Act 1 Scene 5: The Great Hall in Capulet's mansion",
  7. "Act 2 Scene 1: Outside Capulet's mansion",
  8. "Act 2 Scene 2: Capulet's orchard",
  9. "Act 2 Scene 3: Outside Friar Lawrence's cell",
  10. "Act 2 Scene 4: A street in Verona",
  11. "Act 2 Scene 5: Capulet's mansion",
  12. "Act 2 Scene 6: Friar Lawrence's cell"
  13. ]

您可以将hasPrefix(_:)方法与romeoAndJuliet数组一起使用,以计算该剧的第一幕中的场景数量:

  1. var act1SceneCount = 0
  2. for scene in romeoAndJuliet {
  3. if scene.hasPrefix("Act 1 ") {
  4. act1SceneCount += 1
  5. }
  6. }
  7. print("There are \(act1SceneCount) scenes in Act 1")
  8. // Prints "There are 5 scenes in Act 1"

类似地,使用该hasSuffix(_:)方法计算Capulet的宅邸和Friar Lawrence的单元中或周围发生的场景数量:

  1. var mansionCount = 0
  2. var cellCount = 0
  3. for scene in romeoAndJuliet {
  4. if scene.hasSuffix("Capulet's mansion") {
  5. mansionCount += 1
  6. } else if scene.hasSuffix("Friar Lawrence's cell") {
  7. cellCount += 1
  8. }
  9. }
  10. print("\(mansionCount) mansion scenes; \(cellCount) cell scenes")
  11. // 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语句遍历字符串,以CharacterUnicode扩展字素簇的形式访问其各个值。使用字符中描述了此过程

或者,以String其他三个符合Unicode的表示形式之一访问值:

  • UTF-8代码单元的集合(通过字符串的utf8属性访问
  • UTF-16代码单元的集合(通过字符串的utf16属性访问
  • 相当于字符串的UTF-32编码形式的21位Unicode标量值的集合(通过字符串的unicodeScalars属性访问

下面示出了每个实施例下面的字符串,它是由所述字符的向上的不同表示Dog或Unicode标),以及🐶字符(或Unicode标):DOUBLE EXCLAMATION MARKU+203CDOG FACEU+1F436

  1. let dogString = "Dog‼🐶"

UTF-8表示形式

您可以String通过对其utf8属性进行迭代来访问其的UTF-8表示形式此属性的类型为String.UTF8View,是一个无符号的8位(UInt8)值的集合,该值用于字符串的UTF-8表示形式的每个字节:

../_images/UTF8_2x.png
  1. for codeUnit in dogString.utf8 {
  2. print("\(codeUnit) ", terminator: "")
  3. }
  4. print("")
  5. // Prints "68 111 103 226 128 188 240 159 144 182 "

在上面的例子中,前三个十进制codeUnit值(68111103)所表示的字符Dog,其UTF-8表示相同的ASCII表示。接下来的三个十进制codeUnit值(226128188)是一个三字节UTF-8表示的字符。最后四个值()是一个四字节UTF-8表示的字符。DOUBLE EXCLAMATION MARKcodeUnit240159144182DOG FACE

UTF-16表示形式

您可以String通过对其utf16属性进行迭代来访问其的UTF-16表示形式此属性的类型为String.UTF16View,它是无符号16位(UInt16)值的集合,字符串的UTF-16表示形式中的每个16位代码单元一个:

../_images/UTF16_2x.png
  1. for codeUnit in dogString.utf16 {
  2. print("\(codeUnit) ", terminator: "")
  3. }
  4. print("")
  5. // Prints "68 111 103 8252 55357 56374 "

再次,前三个codeUnit值(68111103)所表示的字符Dog,其UTF-16代码单元具有相同的值作为字符串的UTF-8表示(因为这些Unicode标量表示ASCII字符)。

第四codeUnit值(8252)是一个十进位等值的十六进制值的203C,它代表了Unicode标U+203C字符。该字符可以表示为UTF-16中的单个代码单元。DOUBLE EXCLAMATION MARK

第五和第六个codeUnit值(5535756374)是字符的UTF-16代理对表示这些值的高代理值(十进制值)和一个低代理值(十进制值)。DOG FACEU+D83D55357U+DC3656374

Unicode标量表示

您可以String通过迭代其unicodeScalars属性来访问值的Unicode标量表示形式此属性是type UnicodeScalarView,它是type值的集合UnicodeScalar

每个属性UnicodeScalar都有一个value返回标量的21位值属性,用一个UInt32表示

../_images/UnicodeScalar_2x.png
  1. for scalar in dogString.unicodeScalars {
  2. print("\(scalar.value) ", terminator: "")
  3. }
  4. print("")
  5. // Prints "68 111 103 8252 128054 "

value前三个属性UnicodeScalar值(68111103)再次表示字符Dog

第四codeUnit值(8252)又是一个十进位等值的十六进制值的203C,它代表了Unicode标U+203C字符。DOUBLE EXCLAMATION MARK

value第五和最后的属性UnicodeScalar128054是一个十进制等效的十六进制值的1F436,它代表了Unicode标U+1F436字符。DOG FACE

作为查询其value属性的替代方法,每个UnicodeScalar值也可以用于构造新String值,例如使用字符串插值:

  1. for scalar in dogString.unicodeScalars {
  2. print("\(scalar) ")
  3. }
  4. // D
  5. // o
  6. // g
  7. // ‼
  8. // 🐶

 

 
posted @ 2018-09-28 19:53  为敢技术  阅读(950)  评论(0编辑  收藏  举报