上一次学习关于变量常量,数据类型,数据类型之间的转换,这次从字符串开始学习。
您可以在您的代码中包含一段预定义的字符串值作为字符串字面量。字符串字面量是由双引号 ( “” ) 包裹着的具有固定顺序的文本字符集。 字符串字面量可以用于为常量和变量提供初始值:
let someString = "Some string literal value"
注意 someString 常量通过字符串字面量进行初始化,Swift 会推断该常量为 String 类型。
注意:
初始化空字符串 (Initializing an Empty String),要创建一个空字符串作为初始值,可以将空的字符串字面量赋值给变量,也可以初始化一个新的 String 实例:
var emptyString = "" // 空字符串字面量
var anotherEmptyString = String() // 初始化方法
// 两个字符串均为空并等价。
您可以通过检查其 Boolean 类型的 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) - 常量字符串不可以被修改。
注意:
在 Objective-C 和 Cocoa 中,您需要通过选择两个不同的类( NSString 和NSMutableString )来指定字符串是否可以被修改。
Swift 的 String 类型是值类型。 如果您创建了一个新的字符串,那么当其进行常量、变量赋值操作,或在函数/方法中传递时,会进行值拷贝。 任何情况下,都会对已有字符串值创建新副本,并对该新副本进行传递或赋值操作。
注意:
与 Cocoa 中的 NSString 不同,当您在 Cocoa 中创建了一个 NSString 实例,并将其传递给一个函数/方法,或者赋值给一个变量,您传递或赋值的是该 NSString 实例的一个引用,除非您特别要求进行值拷贝,否则字符串不会生成新的副本来进行赋值操作。
Swift 默认字符串拷贝的方式保证了在函数/方法中传递的是字符串的值。 很明显无论该值来自于哪里,都是您独自拥有的。 您可以确信传递的字符串不会被修改,除非你自己去修改它。
在实际编译时,Swift 编译器会优化字符串的使用,使实际的复制只发生在绝对必要的情况下,这意味着您将字符串作为值类型的同时可以获得极高的性能。
您可通过 for-in 循环来遍历字符串中的 characters 属性来获取每一个字符的值:
for character in "Dog!?".characters {
print(character)
} // D // o // g // ! // ?
for-in 循环在 For Loops (页 0) 中进行了详细描述。
另外,通过标明一个 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 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 ) 插入到字符串中。 在这个例子中,表达式写为 (Double(multiplier) * 2.5) 并包含在字符串字面量中。
注意:
插值字符串中写在括号中的表达式不能包含非转义双引号 ( ” ) 和反斜杠 ( \ ),并且不能包含回车或换行符。
Unicode 是一个国际标准,用于文本的编码和表示。 它使您可以用标准格式表示来自任意语言几乎所有的字符,并能够对文本文件或网页这样的外部资源中的字符进行读写操作。 Swift 的 String 和 Character 类型是完
全兼容 Unicode 标准的。
Swift 的 String 类型是基于 Unicode 标量 建立的。 Unicode 标量是对应字符或者修饰符的唯一的21位数字,例如 U+0061 表示小写的拉丁字母( LATIN SMALL LETTER A )(” a “), U+1F425 表示小鸡表( FRON
T-FACING BABY CHICK ) (” ? “)。
**注意: **Unicode 码位(code poing) 的范围是 U+0000 到 U+D7FF 或者 U+E000 到 U+10FFFF 。Unicode
标量不包括 Unicode 代理项(surrogate pair) 码位,其码位范围是 U+D800 到 U+DFFF 。
注意不是所有的21位 Unicode 标量都代表一个字符,因为有一些标量是留作未来分配的。已经代表一个典型字符
的标量都有自己的名字,例如上面例子中的 LATIN SMALL LETTER A 和 FRONT-FACING BABY CHICK 。
字符串字面量的特殊字符 (Special Characters in String Literals)
**字符串字面量可以包含以下特殊字符:
? 转义字符 \0 (空字符)、 \ (反斜线)、 \t (水平制表符)、 \n (换行符)、 \r (回车符)、 \” (双引号)、 \’ (单引
号)。**
? Unicode 标量,写成 \u{n} (u为小写),其中 n 为任意一到八位十六进制数且可用的 Unicode 位码。
下面的代码为各种特殊字符的使用示例。 wiseWords 常量包含了两个双引号。 dollarSign 、 blackHeart 和 s
parklingHeart 常量演示了三种不同格式的 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
如果想要获得一个字符串中 Character 值的数量,可以使用字符串的 characters 属性的 count 属性:
let unusualMenagerie = "Koala ?, Snail ?, Penguin ?, Dromedary ?"
print("unusualMenagerie has \(unusualMenagerie.characters.count) characters")
// 打印输出 "unusualMenagerie has 40 characters"
注意在 Swift 中,使用可拓展的字符群集作为 Character 值来连接或改变字符串时,并不一定会更改字符串的字
符数量。
例如,如果你用四个字符的单词 cafe 初始化一个新的字符串,然后添加一个 COMBINING ACTUE ACCEN
T ( U+0301 )作为字符串的结尾。最终这个字符串的字符数量仍然是 4 ,因为第四个字符是 e ,而不是 e :
var word = "cafe"
print("the number of characters in \(word) is \(word.characters.count)")
// 打印输出 "the number of characters in cafe is 4"
word += "\u{301}" // COMBINING ACUTE ACCENT, U+0301
print("the number of characters in \(word) is \(word.characters.count)")
// 打印输出 "the number of characters in café is 4"
注意:
可扩展的字符群集可以组成一个或者多个 Unicode 标量。这意味着不同的字符以及相同字符的不同表示方式可
能需要不同数量的内存空间来存储。所以 Swift 中的字符在一个字符串中并不一定占用相同的内存空间数量。因
此在没有获取字符串的可扩展的字符群的范围时候,就不能计算出字符串的字符数量。如果您正在处理一个长字
符串,需要注意 characters 属性必须遍历全部的 Unicode 标量,来确定字符串的字符数量。
另外需要注意的是通过 characters 属性返回的字符数量并不总是与包含相同字符的 NSString 的 length 属性
相同。 NSString 的 length 属性是利用 UTF-16 表示的十六位代码单元数字,而不是 Unicode 可扩展的字符
群集。作为佐证,当一个 NSString 的 length 属性被一个Swift的 String 值访问时,实际上是调用了 utf16Cou
nt 。
你可以通字符串的属性和方法来访问和读取它,当然也可以用下标语法完成。
每一个 String 值都有一个关联的索引( index )类型String.Index ,它对应着字符串中的每一个 Character 的位置。
前面提到,不同的字符可能会占用不同数量的内存空间,所以要知道 Character 的确定位置,就必须从 String开头遍历每一个 Unicode 标量直到结尾。因此,Swift 的字符串不能用整数(integer)做索引。
使用 startIndex 属性可以获取一个 String 的第一个 Character 的索引。使用 endIndex 属性可以获取最后一个Character 的后一个位置的索引。因此, endIndex 属性不能作为一个字符串的有效下标。如果 String 是空串, startIndex 和 endIndex 是相等的。
通过调用 String.Index 的 predecessor() 方法,可以立即得到前面一个索引,调用 successor() 方法可以立即得到后面一个索引。任何一个 String 的索引都可以通过锁链作用的这些方法来获取另一个索引,也可以调用 advancedBy(_:) 方法来获取。但如果尝试获取出界的字符串索引,就会抛出一个运行时错误。
你可以使用下标语法来访问 String 特定索引的 Character 。
let greeting = "Guten Tag!"
greeting[greeting.startIndex]
// G
greeting[greeting.endIndex.predecessor()]
// !
greeting[greeting.startIndex.successor()]
// u
let index = greeting.startIndex.advancedBy(7)
greeting[index]
// a
试图获取越界索引对应的 Character ,将引发一个运行时错误。
greeting[greeting.endIndex] // error
greeting.endIndex.successor() // error
使用 characters 属性的 indices 属性会创建一个包含全部索引的范围( Range ),用来在一个字符串中访问单个字符。
for index in greeting.characters.indices {
print("\(greeting[index]) ", terminator: "")
}
// 打印输出 "G u t e n T a g !"
调用 insert(_:atIndex:) 方法可以在一个字符串的指定索引插入一个字符。
var welcome = "hello"
welcome.insert("!", atIndex: welcome.endIndex)
// welcome now 现在等于 "hello!"
调用 insertContentsOf(_:at:) 方法可以在一个字符串的指定索引插入一个字符串。
welcome.insertContentsOf(" there".characters, at: welcome.endIndex.predecessor())
// welcome 现在等于 "hello there!"
调用 removeAtIndex(_:) 方法可以在一个字符串的指定索引删除一个字符。
welcome.removeAtIndex(welcome.endIndex.predecessor())
// welcome 现在等于 "hello there"
调用 removeRange(_:) 方法可以在一个字符串的指定索引删除一个子字符串。
let range = welcome.endIndex.advancedBy(-6)..<welcome.endIndex
welcome.removeRange(range)
// welcome 现在等于 "hello"
Swift 提供了三种方式来比较文本值:字符串字符相等、前缀相等和后缀相等。
字符串/字符可以用等于操作符( == )和不等于操作符( != )
let quotation = "We're a lot alike, you and I."
let sameQuotation = "We're a lot alike, you and I."
if quotation == sameQuotation {
print("These two strings are considered equal")
}
// 打印输出 "These two strings are considered equal"
通过调用字符串的 hasPrefix(:) / hasSuffix(:) 方法来检查字符串是否拥有特定前缀/后缀,两个方法均接收一
个 String 类型的参数,并返回一个布尔值。
下面的例子以一个字符串数组表示莎士比亚话剧《罗密欧与朱丽叶》中前两场的场景位置:
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"
]
您可以调用 hasPrefix(_:) 方法来计算话剧中第一幕的场景数:
var act1SceneCount = 0
for scene in romeoAndJuliet {
if scene.hasPrefix("Act 1 ") {
++act1SceneCount
}
}
print("There are \(act1SceneCount) scenes in Act 1")
// 打印输出 "There are 5 scenes in Act 1"
相似地,您可以用 hasSuffix(_:) 方法来计算发生在不同地方的场景数:
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
}
}
print("\(mansionCount) mansion scenes; \(cellCount) cell scenes")
// 打印输出 "6 mansion scenes; 2 cell scenes
字符串基本就这些操作了。
下面是我的一个学习Swift开源库。