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

★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★
➤微信公众号:山青咏芝(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"StringStringCharacter

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

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

注意

Swift的String类型与Foundation的NSString类是桥接的。Foundation还扩展String为公开定义的方法NSString。这意味着,如果您导入Foundation,则可以NSStringString不进行强制转换的情况下访问这些方法。

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

字符串文字

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

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

  1. let someString = "Some string literal value"

需要注意的是斯威夫特,推测型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. """

可以缩进多行字符串以匹配周围的代码。在右引号mark(""")之前的空格告诉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可以通过将特定分配给变量(在这种情况下可以修改)或常量(在这种情况下不能修改)来指示特定是否可以修改(或变异):

  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中的字符串变异,您可以在两个类(NSStringNSMutableString)之间进行选择,以指示字符串是否可以变异。

字符串是值类型

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

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

在幕后,Swift的编译器优化了字符串的使用,因此只有在绝对必要的情况下才会进行实际的复制。这意味着在使用字符串作为值类型时,您总能获得出色的性能。

使用角色

您可以通过使用- 循环遍历字符串来访问a的各个Character值:Stringforin

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

forin环中描述对于-在循环中

或者,您可以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!"

注意

您不能将a 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

在上面的代码中,级联badStartend产生两行字符串,这是不期望的结果。因为最后一行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也是字符串中较大表达式的一部分。此表达式计算值,并将result()插入到字符串中。在这种情况下,表达式被写为当它包含在字符串文字中时。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+0061for ()或for ()。LATIN SMALL LETTER A"a"U+1F425FRONT-FACING BABY CHICK"?"

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

扩展的Grapheme集群

Swift Character类型的每个实例都代表一个扩展的字形集群。扩展字形集群是一个或多个Unicode标量的序列(当组合时)产生单个人类可读字符。

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

在这两种情况下,字母é都表示为单个Swift Character值,表示扩展的字形集群。在第一种情况下,集群包含单个标量; 在第二种情况下,它是两个标量的集群:

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

扩展的字形集群是将许多复杂的脚本字符表示为单个Character值的灵活方式。例如,韩语字母表中的韩语音节可以表示为预先组合或分解的序列。这两个表示都符合CharacterSwift中的单个值:

  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值意味着字符串连接和修改可能并不总是会影响字符串的字符数。

例如,如果使用四个字符的单词初始化一个新字符串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相同。a的长度NSString基于字符串的UTF-16表示中的16位代码单元的数量,而不是字符串中Unicode扩展的字形集群的数量。

访问和修改字符串

您可以通过其方法和属性或使用下标语法来访问和修改字符串。

字符串索引

每个String值都有一个关联的索引类型String.Index它对应Character于字符串中每个值的位置。

如上所述,不同的字符可能需要不同的内存量来存储,因此为了确定哪个Character位于特定位置,您必须从开头或结尾迭代每个Unicode标量String。因此,Swift字符串不能用整数值索引。

使用该startIndex属性访问第Character一个的位置String。该endIndex属性是a中最后一个字符后的位置String。因此,该endIndex属性不是字符串下标的有效参数。如果a 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的值。您可以使用a StringSubstring值调用此类函数。

比较字符串

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标量组成的。

例如,()在规范上等效于()后跟()。这两个扩展的字形集合都是表示字符的有效方式,因此它们被认为是规范等价的: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 are not equivalent.")
  5. }
  6. // Prints "These two characters are not 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幕中的场景数量:

  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表示。您可以使用forin语句迭代字符串,以CharacterUnicode扩展字形集群的形式访问其各个值。使用字符中描述了此过程。

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

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

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

  1. let dogString = "Dog‼?"

UTF-8表示法

您可以String通过迭代其utf8属性来访问a的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属性来访问a的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标量表示。此属性的类型是类型UnicodeScalarView值的集合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. // ?

转载于:https://www.cnblogs.com/strengthen/p/9720541.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值