Strings and Characters
字符串是字符的有序集合,例如“hello,world”、"你好,中国"。Swift中的字符串用String表示,返回的字符(character)类型的集合。
Swift中的字符串和字符类型提供了一种快速、符合Unicode码的方式来操作代码中的文本。类似与C的字符串语法,Swift中的字符串的创建和操作语法是轻量级的和可读的。字符串的连接就是通过加号(+)将2个字符串串联在一起。和Swift中其他类型的值一样,通过在变量或常量之间的选择来管理字符串的可变性。抛开语法的简便性不说,Swift中的字符串类型是一个快速,时髦的字符串实现。每一个字符串都是由独立编码格式的unicode字符组成。提供各式各样的Unicode形式处理它。
字符串也用于将常量、变量、文本常量、表达式等擦入到一个长的字符串中,成为字符串插值。创建普通的字符串用于显示、存储、打印显得很容易。
注意
Swift的字符串类型与Fundation的NSString类可以无缝连接。如果你在Cocoa或者Cocoa Touch中使用过Fundations 框架,除了这篇文章描述的String的特性外,
NSString api允许调用任何你创建的值。
如果想了解更多的关于Cocoa和Cocoa Touch如何使用字符串的知识,请参看<em class="u-book"><a target=_blank href="https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/BuildingCocoaApps/index.html#//apple_ref/doc/uid/TP40014216" target="_self">Using Swift with Cocoa and Objective-C</a></em>.一文。
字符串常量
在你的代码中可以加入预定义的字符串值作为字符串常量。一个字符串常量是一个固定的文本字符,被一对双引号(“”)包裹。
字符串常量可以为常量或者变量提供初始化值。
let someString = "Some string literal value"
Swift会推断出someString常量是一个String类型的值,因为它是用字符串常量初始化的。
字符串常量可以包含下列特殊的字符:
- 转义字符:null字符(\0)、反斜杠(\\)、制表符(\t)、换行符(\n)、回车符(\r)、双引号(\")、单引号(\')
- 单个字节的unicode数量,写成\xnn,nn代表2个16位的数。
- 双字节的unicode数量,写出\unnnn,nnnn是4个16位的数。
- 4字节的unicode数量,写成\Unnnnnnnn,nnnnnnnn代表8个16位的数。
初始化一个空字符串
创建一个空字符串作为一个长字符串的起点,或者给变量附上一个空字符串的值,或者初始化一个新的String对象。
var emptyString = "" // empty string literal
var anotherEmptyString = String() // initializer syntax
// these two strings are both empty, and are equivalent to each other
你可以通过调用字符串的isEmpty属性来判断字符串是否为空。
if emptyString.isEmpty {
println("Nothing to see here")
}
// prints "Nothing to see here"
字符串可变
通过将值赋给变量(可变)或者将值赋给常量(不可变)
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
注意
这种方式是不同于OC和Cocoa中的字符串操作的,OC和Cocoa是在两个类(NSString和NSMutableString)中进行选择,来决定是否可变的
字符串值类型
Swift中的字符串是值类型的。如果你创建一个新的字符串值,当你传递给函数或方法、变量或者常量时,传递的是String的值。在这种情况下,已存在的String的值的复制版本会被创建,传递和分配的新复制的值而不是原始值。值类型的描述参考Structures and Enumerations Are Value Types一文。
注意
这种表现不同于Cocoa中的NSString。当你在Cocoa中创建NSString实例时,你传递给方法、函数、变量和常量的是对象的引用,一般情况下不会有copy版本的出现。
Swift中String的默认copy的特性确保了当一个方法和函数传递过来一个String值,你不用在意它的原始值是否被修改,因为一般情况下都不会修改到原始值。
在后台,Swift的编译器优化使用字符串确保只有当有绝对需要的时候才复制字符串。这意味着在处理字符串时性能会非常优越。
字符操作
Swift的字符串代表着一组字符顺序的排列。每一个字符的值代表一个Unicode字符。你可以通过for循环来处理字符串中的每一个字符:
for循环的只是参考For Loops一文。
或者你可以创建独立的字符变量或常量,通过在字符串常量后加上注释的方式。
let yenSign: Character = "¥"
计算字符
如果要计算某个字符中特定字符的个数,可以调用全局函数countElements然后传递唯一参数:字符串。
注意
不同的Unicode字符以及相同的字符具有的不同表现需要不同的存储空间。因此,Swift中的字符串的字符不都是分配相同的存储空间。因此,如果想计算字符串的存储空间,
必须迭代计算每一个字符的空间。如果需要处理特殊的长字符串,知道有countElements这个函数必须迭代取出字符串中的每个字符的空间来计算字符串的数量。
对于同一个字符串,Swift中countElements和OC中的NSString的属性length返回比一定是一样的,NSString的长度计算是以字符串的UTF-16的表现形式中的16比特代码集的数量,
而不是字符串中的字符数来计算的。为了表达这种事实,当处理Swift的字符串值时,NSString的length属性通过调用utf16count来计算。
字符串和字符的连接
字符串和字符可以通过加号(+)连接在一起组成一个新的字符串。
let string1 = "hello"
let string2 = " there"
let character1: Character = "!"
let character2: Character = "?"
let stringPlusCharacter = string1 + character1 // equals "hello!"
let stringPlusString = string1 + string2 // equals "hello there"
let characterPlusString = character1 + string1 // equals "!hello"
let characterPlusCharacter = character1 + character2 // equals "!?"
你也可以通过加等(+=)符号将一个字符串或者字符附加到一个已存在的字符串变量上:
var instruction = "look over"
instruction += string2
// instruction now equals "look over there"
var welcome = "good morning"
welcome += character1
// welcome now equals "good morning!"
注意
你不能将字符串或字符添加到一个字符变量上,因为字符变量值能包含一个单独的字符。
擦入字符串
字符串擦值是通过在一个字符串表达式中混合常量、变量、文字和表达式的方式构造一个新的字符串值。你擦入字符串表达式的每个元素被会用括号包裹且前面都有一个反斜杠。
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)擦入到字符串表达式中。
注意
在要擦值的字符串中,你写进括号的表达式不可以包含非转义的的双引号(")或者反斜杠(\)、回车符换行符。
字符串比较
Swift提供三种方式比较字符串的值:字符串相等,前等,后等。
字符串相等
两个字符串相同顺序上的字符是相等的,那么这两个字符串就是相等的。
let quotation = "We're a lot alike, you and I."
let sameQuotation = "We're a lot alike, you and I."
if quotation == sameQuotation {
println("These two strings are considered equal")
}
// prints "These two strings are considered equal"
前等和后等
判断一个字符串是否有特殊字符串的前缀或者后缀,可以调用字符串的hasPrefix
和hasSuffix方法,都是传一个字符串类似参数然后返回一个Bool的值。方法执行逐字符比较基本的字符串和前缀或后缀字符串。
下面的例子中,字符串数组代表的是截取自莎士比亚的前两个章节中场景。
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"
]
你可以调用romeAndJuliet的hasPrefix来计算数组中有多少个元素含有“Act 1”前缀。
var act1SceneCount = 0
for scene in romeoAndJuliet {
if scene.hasPrefix("Act 1 ") {
++act1SceneCount
}
}
println("There are \(act1SceneCount) scenes in Act 1")
// prints "There are 5 scenes in Act 1"
类似的,你也可以调用hasSuffix来计算数组中有多少个元素含有Cappulet's和Friar Lawrence’s cell后缀.
var mansionCount = 0
var cellCount = 0
for scene in romeoAndJuliet {
if scene.hasSuffix("Capulet's mansion") {
++mansionCount
} else if scene.hasSuffix("Friar Lawrence's cell") {
++cellCount
}
}
println("\(mansionCount) mansion scenes; \(cellCount) cell scenes")
// prints "6 mansion scenes; 2 cell scenes"
字符串的大小写
你可以使用字符串的uppercaseString
和 lowercaseString属性来处理字符串的大小写版本。
let normal = "Could you help me, please?"
let shouty = normal.uppercaseString
// shouty is equal to "COULD YOU HELP ME, PLEASE?"
let whispered = normal.lowercaseString
// whispered is equal to "could you help me, please?"
Unicode
Unicode是国际统一的字符编码标准,这种标准让你几乎可以处理标准形式中的任何语言的任何字符串,包括读写来自外部资源(文本文件和网页文件)的字符。
Swift中字符串和字符完全符合Unicode标准。它支持下面所描述的不同的unicode编码。
Unicode术语
Unicode中的每一个字符都可以用一个或多个unicode标量来表示。一个unicode标量对于一个字符或标识符来说就是一个21位的数字(或者名称)。例如拉丁字母小写字母A("a")用Unicode标量表示就是U+0061,小鸡的正面就用U+1F425
表示。
当一个unicode被写入一个文本文件或者其他存储中时,那些unicode标量会在几个unicode定义格式中的一个上进行编码。每个格式编码的字符串小块称为代码集,包括uft-8(用8bit编码字符串)和utf-16(16bit编码字符串)
unicode字符串的表示
Swift提供多个不同的方式去处理unicode字符串的表示。
你可以使用for-in语句去递归遍历字符串来处理单个unicode的字符,这个过程的详细描述参见Working with Characters
或者,处理下面三种符合unicode编码之一的字符串的值:
- UFT-8代码集的集合(通过字符串的utf8属性访问)
- UFT-16代码集的集合(通过字符串的utf16属性访问)
- 21bitunicode标量值的集合(通过字符串的
unicodeScalars
属性访问)
下面的每一个例子展示了由字符D,o,g,!和狗脸(unicode标量U+1F436
)组成的字符串的不同的表示形式:
UTF-8
你可以通过迭代utf8属性来处理UTF-8表现形式的字符串。这个属性是UTF8View类型的,字符串中的每个字符都是无符号8bit(UInt8)值的集合。
for codeUnit in dogString.utf8 {
print("\(codeUnit) ")
}
print("\n")
// 68 111 103 33 240 159 144 182
上面的例子中,前面4个10进制数(68 111 103 33)代表了字符D,o,g,!他们的UTF-8表现形式和ASCII码的表现形式是一致的。后面四个数(240 159 144 182)是一个4位UTF-8表现形式,代表的是狗脸这个字符。
UTF-16
和utf8一样,你也可以迭代其utf16属性来处理UTF-16形式的字符串。该属性是UTF16View类型的,UTF16形式字符串中每一位都是16bit的代码集。
for codeUnit in dogString.utf16 {
print("\(codeUnit) ")
}
print("\n")
// 68 111 103 33 55357 56374
首先前四位代表的和UTF8中是一样的,就不再描述了。第五个和第六个codeUnit值代表的是狗脸的UTF16的表现形式,他们表示的是
U+D83D
(55357)和
U+DC36
(56374).
Unicode标量
你可以迭代其unicodeScalars
属性来处理unicode标量表现形式的字符串。该属性是UnicodeScalarView类型,一组UnicodeScalar值的集合.一个unicode标量是一个21bit的unicode码位,既不是主要代理也不是跟踪代理代码点。
每一个UnicodeScalar类型都有一个value属性,该属性会返回一个标量的21bit值,用UInt32值表示。
for scalar in dogString.unicodeScalars {
print("\(scalar.value) ")
}
print("\n")
// 68 111 103 33 128054
前4个值表示的去上面的UTF-8和UTF-16是一样的。第五位是16进制数1F436
的10进制表示法,表示的是狗脸。
查询value属性的另外一种方式就是通过构造一个新的String值来使用UnicodeScalar值。例如在字符串擦值中的应用:
(完!)