Swift 字符串

字符串和字符

字符串是是一系列字符的集合,例如 "hello, world","albatross"。Swift 的字符串通过 String 类型来表示。

Swift 的 String 和 Character 类型提供了一种快速且兼容 Unicode 的方式来处理代码中的文本内容。创建和操作字符串的语法与 C 语言中字符串操作相似,轻量并且易读。通过 + 符号就可以非常简单的实现两个字符串的拼接操作。

尽管语法简易,但 Swift 中的 String 类型的实现却很快速和现代化。每一个字符串都是由编码无关的 Unicode 字符组成,并支持访问字符的多种 Unicode 表示形式。

字符串字面量

你可以在代码里使用一段预定义的字符串值作为字符串字面量。字符串字面量是由一对双引号包裹着的具有固定顺序的字符集。

字符串字面量可以用于为常量和变量提供初始值:

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 编译器其他各行多少空白字符串需要忽略。然而,如果你在某行的前面写的空白字符串超出了关闭引号(""")之前的空白字符串,则超出部分将被包含在多行字符串字面量中。

在上面的例子中,尽管整个多行字符串字面量都是缩进的(源代码缩进),第一行和最后一行没有以空白字符串开始(实际的变量值)。中间一行的缩进用空白字符串(源代码缩进)比关闭引号(""")之前的空白字符串多,所以,它的行首将有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 \"\"\"
"""

扩展字符串分隔符

您可以将字符串文字放在扩展分隔符中,这样字符串中的特殊字符将会被直接包含而非转义后的效果。将字符串放在引号(")中并用数字符号(#)括起来。例如,打印字符串文字 #"Line 1 \ nLine 2"# 打印换行符转义序列(\n)而不是进行换行打印。

如果需要字符串文字中字符的特殊效果,请匹配转义字符(\)后面添加与起始位置个数相匹配的 # 符。 例如,如果您的字符串是 #"Line 1 \ nLine 2"# 并且您想要换行,则可以使用 #“Line 1 \ #nLine 2”# 来代替。 同样,###"Line1 \ ### nLine2"### 也可以实现换行效果。

扩展分隔符创建的字符串文字也可以是多行字符串文字。 您可以使用扩展分隔符在多行字符串中包含文本 """,覆盖原有的结束文字的默认行为。例如:

let threeMoreDoubleQuotationMarks = #"""
Here are three more double 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) - 常量字符串不可以被修改。

使用字符

你可通过 for-in 循环来遍历字符串,获取字符串中每一个字符的值:

for character in "Dog!" {
    print(character)
}
// D
// o
// g
// !

另外,通过标明一个 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"

你可以用 append() 方法将一个字符附加到一个字符串变量的尾部:

let exclamationMark: Character = "!"
welcome.append(exclamationMark)
// welcome 现在等于 "hello there!"

字符串插值

字符串插值是一种构建新字符串的方式,可以在其中包含常量、变量、字面量和表达式。字符串字面量和多行字符串字面量都可以使用字符串插值。你插入的字符串字面量的每一项都在以反斜线为前缀的圆括号中:

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) 并包含在字符串字面量中。

注意插值字符串中写在括号中的表达式不能包含非转义反斜杠(\),并且不能包含回车或换行符。不过,插值字符串可以包含其他字面量。