Swift学习笔记 (六) 字符串和字符(上)

字符串是一系列字符的集合,例如 "hello, world" , "albatross" 。Swift 的字符串通过 String 类型来表示。⽽ String 内容的访问方式有

多种,例如以 Character 值的集合。

Swift 的 String 和 Character 类型提供了一种快速且兼容 Unicode 的方式来处理代码中的文本内容。创建和操作字符串的语法与 C 语⾔

中字符串操作相似,轻量并且易读。通过 + 符号就可以非常简单的实现两个字符串的拼接操作。与 Swift 中其他值一样,能否更改字符

串的值,取决于其被定义为常量还是变量。你可以在已有字符串中插入常量、 变量、字⾯量和表达式从而形成更长的字符串,这一过程

也被成为字符串插值。尤其是在为显示、存储和打印创建自定义字符串时,字符串插值操作尤其有用。

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

符的多种 Unicode 表示形式。

注意

Swift 的 String 类型与 Foundation NSString 类进⾏了⽆缝桥接。Foundation 还对 String 进⾏扩展使其可以访问 NSString 类型中定

义的方法。这意味着调用那些 NSString 的⽅法,你无需进行任何类型转换。

 

字符串字⾯量

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

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

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) - 常量字符串不可以被修改

 

字符串是值类型

在 Swift 中 String 类型是值类型。如果你创建了一个新的字符串,那么当其进⾏常量、变量赋值操作,或在函数/⽅法中传递时,会进

⾏值拷贝。在前述任一情况下,都会对已有字符串值创建新副本,并对该新副本而非原始字符串进⾏传递或赋值操作。值类型在结构体

和枚举是值类型章节中进⾏了详细描述。

Swift 默认拷贝字符串的⾏为保证了在函数/⽅法向你传递的字符串所属权属于你,无论该值来自于哪里。你可以确信传递的字符串不会

被修改,除非你⾃己去修改它。

在实际编译时,Swift 编译器会优化字符串的使用,使实际的复制只发生在绝对必要的情况下,这意味着你将字符串作为值类型的同时

可以获得极高的性能。

 

使⽤字符 

你可通过 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"

你也可以通过加法赋值运算符( += )将一个字符串添加到一个已经存在字符串变量上:

var instruction = "look over"

instruction += string2                              // instruction 现在等于 "look over there"

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

let exclamationMark: Character = "!"

welcome.append(exclamationMark)      // welcome 现在等于 "hello there!"

 

注意

你不能将一个字符串或者字符添加到一个已经存在的字符变量上,因为字符变量只能包含一个字符。

如果你需要使用多行字符串字⾯量来拼接字符串,并且你需要字符串每一⾏都以换行符结尾,包括最后一行:

let badStart = """

one

two

"""

 

let end = """

three

"""
print(badStart + end)

// 打印两行:

// one

// twothree

 

let goodStart = """

one

two

 

"""

print(goodStart + end)

// 打印三行:

// one

// two

// three

上⾯的代码,把 badStart 和 end 拼接起来的字符串非我们想要的结果。因为 badStart 最后一⾏没有换⾏符, 它与 end 的第⼀行结合到

了一起。相反的, goodStart 的每一行都以换行符结尾,所以它与 end 拼接的字符串总共有三行,正如我们期望的那样。

 

字符串插值

字符串插值是一种构建新字符串的⽅式,可以在其中包含常量、变量、字⾯量和表达式。字符串字⾯量和多⾏字符串字面量都可以使⽤

用字符串插值。你插入的字符串字⾯量的每一项都在以反斜线为前缀的圆括号中:

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

注意

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

量。

Unicode

Unicode是⼀个⽤于在不同书写系统中对文本进行编码、表示和处理的国际标准。它使你可以用标准格式表示来自任意语言几乎所有的

字符,并能够对⽂本文件或⽹页这样的外部资源中的字符进⾏读写操作。Swift 的 String 和 Character 类型是完全兼容 Unicode 标准

的。

 

Unicode 标量

Swift 的 String 类型是基于 Unicode 标量建立的。Unicode 标量是对应字符或者修饰符的唯一的 21 位数字,例如U+0061 表示小写的

拉丁字母( LATIN SMALL LETTER A )(" a "), U+1F425 表示小鸡表情( FRONT-FACINGBABY CHICK )(" ?")。

请注意,并非所有 21 位 Unicode 标量值都分配给字符,某些标量被保留用于将来分配或用于 UTF-16 编码。已分配的标量值通常也有

一个名称,例如上⾯示例中的 LATIN SMALL LETTER A 和 FRONT-FACING BABY CHICK。

 

可扩展的字形群集

每一个 Swift 的 Character 类型代表一个可扩展的字形群。⽽一个可扩展的字形群构成了人类可读的单个字符,它由一个或多个(当组

合时) Unicode 标量的序列组成。

举个例子,字⺟ é 可以用单一的 Unicode 标量 é ( LATIN SMALL LETTER E WITH ACUTE , 或者 U+00E9 )来表示。然而一个标准的字母 

e ( LATIN SMALL LETTER E 或者 U+0065 ) 加上一个急促⾳音( COMBINING ACTUE ACCENT )的标量( U+0301 ),这样一对标量就表示

了同样的字⺟ é 。 这个急促重音的标量形象的将 e 转换成了é。

在这两种情况中,字⺟ é 代表了一个单一的 Swift 的 Character 值,同时代表了一个可扩展的字形群。在第一种情况,这个字形群包含

一个单一标量;⽽在第二种情况,它是包含两个标量的字形群:

let eAcute: Character = "\u{E9}"                                        // é

let combinedEAcute: Character = "\u{65}\u{301}"          // e 后⾯面加上 ́

// eAcute 是 é, combinedEAcute 是 é

可扩展的字形集是一个将许多复杂的脚本字符表示为单个字符值的灵活方式。例如,来自朝鲜语字母表的韩语音节能表示为组合或分解

的有序排列。在 Swift 都会表示为同一个单一的 Character 值:

let precomposed: Character = "\u{D55C}"                                     // 한

let decomposed: Character = "\u{1112}\u{1161}\u{11AB}"             // ᄒ, ᅡ, ᆫ

// precomposed 是 한, decomposed 是 한

可拓展的字符群集可以使用包围记号(例如 COMBINING ENCLOSING CIRCLE 或者 U+20DD )的标量包围其他 Unicode 标量,作为一

个单一的 Character 值:

let enclosedEAcute: Character = "\u{E9}\u{20DD}"                    // enclosedEAcute 是 é⃝

地域性指示符号的 Unicode 标量可以组合成一个单一的 Character 值,例如 REGIONAL INDICATOR SYMBOL LETTER U ( U+1F1FA )

和 REGIONAL INDICATOR SYMBOL LETTER S ( U+1F1F8 ):

let regionalIndicatorForUS: Character = "\u{1F1FA}\u{1F1F8}"      // regionalIndicatorForUS 是??

 

计算字符数量

如果想要获得一个字符串中 Character 值的数量,可以使用 count 属性:

let unusualMenagerie = "Koala ?, Snail ?, Penguin ?, Dromedary ?"

print("unusualMenagerie has \(unusualMenagerie.count) characters")

// 打印输出“unusualMenagerie has 40 characters”

注意在 Swift 中,使用可拓展的字符群集作为 Character 值来连接或改变字符串时,并不一定会更改字符串的字符数量。

例如,如果你用四个字符的单词 cafe 初始化一个新的字符串,然后添加一个 COMBINING ACTUE ACCENT ( U+0301 ) 作为字符串的结

尾。最终这个字符串的字符数量仍然是 4 ,因为第四个字符是 é ,⽽不是 e :

var word = "cafe"

print("the number of characters in \(word) is \(word.count)")             // 打印输出“the number of characters in cafe is 4”

word += "\u{301}" // 拼接一个重音,U+0301

print("the number of characters in \(word) is \(word.count)")             // 打印输出“the number of characters in café is 4”

注意

可扩展的字形群可以由多个 Unicode 标量组成。这意味着不同的字符以及相同字符的不同表示方式可能需要不同数量的内存空间来存

储。所以 Swift 中的字符在一个字符串中并不一定占用相同的内存空间数量。因此在没有获取字符串的可扩展的字符群的范围时候,就

不能计算出字符串的字符数量。如果你正在处理一个长字符串,需要注意 count 属性必须遍历全部的 Unicode 标量,来确定字符串的

字符数量。

另外需要注意的是通过 count 属性返回的字符数量并不总是与包含相同字符的 NSString 的 length 属性相同。 NSString 的 length 属

性是利用 UTF-16 表示的⼗六位代码单元数字,⽽不是 Unicode 可扩展的字符群集。

 

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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值