初始化空字符串 (Initializing an Empty String)
- 要创建一个空字符串作为初始值,可以将空的字符串字面量赋值给变量,也可以初始化一个新的String实例:
- 可以通过检查其Bool类型的isEmpty属性来判断该字符串是否为空:
var emptyString = "" // empty string literal
var anotherEmptyString = String() // initializer syntax
// these two strings are both empty, and are equivalent to each other
if emptyString.isEmpty {
print("Nothing to see here")
}
// Prints "Nothing to see here"
- 没有@符号
- isEmpty是属性,不是方法
- 多用String,少用或者不用NSString
字符串可变性 (String Mutability)
- 您可以通过将一个特定字符串分配给一个变量(var)来对其进行修改,或者分配给一个常量(let)来保证其不会被修改:
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
在 Objective-C 和 Cocoa 中,您需要通过选择两个不同的类(NSString和NSMutableString)来指定字符串是否可以被修改。
字符串是值类型(Strings Are Value Types)
- Swift 的String类型是值类型。 如果您创建了一个新的字符串,那么当其进行常量、变量赋值操作,或在函数/方法中传递时,会进行值拷贝。
- Swift 默认字符串拷贝的方式保证了在函数/方法中传递的是字符串的值。
- 在实际编译时,Swift 编译器会优化字符串的使用,使实际的复制只发生在绝对必要的情况下,这意味着您将字符串作为值类型的同时可以获得极高的性能。
在 Objective-C 中,NSString是引用类型,一般用copy修饰,不用strong修饰,就是为了获得值类型的效果。
使用字符(Working with Characters)
- 您可通过for-in循环来遍历字符串中的characters属性来获取每一个字符的值
for character in "Dog!🐶".characters {
print(character)
}
// D
// o
// g
// !
// 🐶
- 字符串可以通过传递一个值类型为Character的数组作为自变量来初始化:
let catCharacters: [Character] = ["C", "a", "t", "!", "🐱"]
let catString = String(catCharacters)
print(catString)
// Prints "Cat!🐱"
连接字符串和字符 (Concatenating Strings and Characters)
- 字符串可以通过加法运算符(+)相加在一起(或称“连接”)创建一个新的字符串:
- 您也可以通过加法赋值运算符 (+=) 将一个字符串添加到一个已经存在字符串变量上:
- 您可以用append()方法将一个字符附加到一个字符串变量的尾部:
let string1 = "hello"
let string2 = " there"
var welcome = string1 + string2
// welcome 现在等于 "hello there"
var instruction = "look over"
instruction += string2
// instruction 现在等于 "look over there"
let exclamationMark: Character = "!"
welcome.append(exclamationMark)
// welcome 现在等于 "hello there!"
- 不能将一个字符串或者字符添加到一个已经存在的字符变量上,因为字符变量只能包含一个字符
- 不能将一个字符串和一个字符变量直接向加(+),两者是不同类型
字符串插值 (String Interpolation)
字符串插值是一种构建新字符串的方式,可以在其中包含常量、变量、字面量和表达式。 您插入的字符串字面量的每一项都在以反斜线为前缀的圆括号中:
let multiplier = 3
let message = "\(multiplier) times 2.5 is \(Double(multiplier) * 2.5)"
// message is "3 times 2.5 is 7.5"
Unicode
Swift 的String和Character类型是完全兼容 Unicode 标准的。
Unicode 标量(Unicode Scalars)
Unicode 标量是对应字符或者修饰符的唯一的21位数字
字符串字面量的特殊字符 (Special Characters in String Literals)
- 转义字符\0(空字符)、\\(反斜线)、\t(水平制表符)、\n(换行符)、\r(回车符)、"(双引号)、'(单引号)。
- Unicode 标量,写成\u{n}(u为小写),其中n为任意一到八位十六进制数且可用的 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
可扩展的字形群集(Extended Grapheme Clusters)
每一个 Swift 的Character类型代表一个可扩展的字形群。 一个可扩展的字形群是一个或多个可生成人类可读的字符 Unicode 标量的有序排列。
let eAcute: Character = "\u{E9}" // é
let combinedEAcute: Character = "\u{65}\u{301}" // e 后面加上 ́
// eAcute 是 é, combinedEAcute 是 é
let precomposed: Character = "\u{D55C}" // 한
let decomposed: Character = "\u{1112}\u{1161}\u{11AB}" // ᄒ, ᅡ, ᆫ
// precomposed 是 한, decomposed 是 한
let enclosedEAcute: Character = "\u{E9}\u{20DD}"
// enclosedEAcute 是 é⃝
let regionalIndicatorForUS: Character = "\u{1F1FA}\u{1F1F8}"
// regionalIndicatorForUS 是 🇺🇸
输入表情,国旗等,比如QQ中的那些头像什么的,可以考虑不用gif加对照表的方法了
计算字符数量 (Counting Characters)
- 如果想要获得一个字符串中Character值的数量,可以使用字符串的characters属性的count属性:
let unusualMenagerie = "Koala 🐨, Snail 🐌, Penguin 🐧, Dromedary 🐪"
print("unusualMenagerie has \(unusualMenagerie.characters.count) characters")
// 打印输出 "unusualMenagerie has 40 characters"
- 注意在 Swift 中,使用可拓展的字符群集作为Character值来连接或改变字符串时,并不一定会更改字符串的字符数量。
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
word += "\u{301}" // COMBINING ACUTE ACCENT, U+0301; 后缀,加再多也不影响字数
word += "\u{301}" // COMBINING ACUTE ACCENT, U+0301
print("the number of characters in \(word) is \(word.characters.count)")
print("NSString length in \(word) is \((word as NSString).length)")
// 打印输出 "the number of characters in café is 4"
// 打印输出 "NSString length in café́́ is 7"
通过characters属性返回的字符数量并不总是与包含相同字符的NSString的length属性相同。NSString的length属性是利用 UTF-16 表示的十六位代码单元数字,而不是 Unicode 可扩展的字符群集。当一个NSString的length属性被一个Swift的String值访问时,实际上是调用了utf16Count
访问和修改字符串 (Accessing and Modifying a String)
字符串索引 (String Indices)
- Swift 的字符串不能用整数(integer)做索引
- 使用startIndex属性可以获取一个String的第一个Character的索引
- 使用endIndex属性可以获取最后一个Character的后一个位置的索引。(是最后一个字符的后一个,不是最后一个;直接访问endIndex会崩溃)
- 如果String是空串,startIndex和endIndex是相等的。
- 通过调用String.Index的predecessor()方法,可以立即得到前面一个索引
- 调用successor()方法可以立即得到后面一个索引。
- 可以调用advancedBy(_:)方法来获取其他的index
- 使用characters属性的indices属性会创建一个包含全部索引的范围(Range),用来在一个字符串中访问单个字符
- 试图获取越界索引对应的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
for index in greeting.characters.indices {
print("\(greeting[index]) ", terminator: "")
}
// 打印输出 "G u t e n T a g ! "
- String的index不是整数这个特性让人难以理解,难于使用;这点苹果做得很差劲
- 在不需要考虑Unicode的情况下,转换为NSString,用整数下标,好理解一点
插入和删除 (Inserting and Removing)
- 调用insert(_:atIndex:)方法可以在一个字符串的指定索引插入一个字符。
- 调用insertContentsOf(_:at:)方法可以在一个字符串的指定索引插入一个字符串。
- 调用removeAtIndex(_:)方法可以在一个字符串的指定索引删除一个字符。
- 调用removeRange(_:)方法可以在一个字符串的指定索引删除一个子字符串。
var welcome = "hello"
welcome.insert("!", atIndex: welcome.endIndex)
// welcome now 现在等于 "hello!"
welcome.insertContentsOf(" there".characters, at: welcome.endIndex.predecessor())
// welcome 现在等于 "hello there!"
welcome.removeAtIndex(welcome.endIndex.predecessor())
// welcome 现在等于 "hello there"
let range = welcome.endIndex.advancedBy(-6)..<welcome.endIndex
welcome.removeRange(range)
// welcome 现在等于 "hello"
- 删除和插入函数不同,字符和字符串函数不同,关于插入删除总共有4个不同的函数
- index和range都不是整数,而是像C语言中指针移动的概念
- 关于index和插入删除操作,还是将String转化为NSString来得方便 STRING 还是 NSSTRING
比较字符串 (Comparing Strings)
- 字符串/字符可以用等于操作符(==)和不等于操作符(!=)
- 如果两个字符串(或者两个字符)的可扩展的字形群集是标准相等的,那就认为它们是相等的。
- 通过调用字符串的hasPrefix(:)/hasSuffix(:)方法来检查字符串是否拥有特定前缀/后缀
// "Voulez-vous un café?" 使用 LATIN SMALL LETTER E WITH ACUTE
let eAcuteQuestion = "Voulez-vous un caf\u{E9}?"
// "Voulez-vous un café?" 使用 LATIN SMALL LETTER E and COMBINING ACUTE ACCENT
let combinedEAcuteQuestion = "Voulez-vous un caf\u{65}\u{301}?"
if eAcuteQuestion == combinedEAcuteQuestion {
print("These two strings are considered equal")
}
// 打印输出 "These two strings are considered equal"
let latinCapitalLetterA: Character = "\u{41}"
let cyrillicCapitalLetterA: Character = "\u{0410}"
if latinCapitalLetterA != cyrillicCapitalLetterA {
print("These two characters are not equivalent")
}
// 打印 "These two characters are not equivalent"
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"
]
var act1SceneCount = 0
for scene in romeoAndJuliet {
if scene.hasPrefix("Act 1 ") {
act1SceneCount += 1
}
}
print("There are \(act1SceneCount) scenes in Act 1")
// 打印输出 "There are 5 scenes in Act 1"
var mansionCount = 0
var cellCount = 0
for scene in romeoAndJuliet {
if scene.hasSuffix("Capulet's mansion") {
mansionCount += 1
} else if scene.hasSuffix("Friar Lawrence's cell") {
cellCount += 1
}
}
print("\(mansionCount) mansion scenes; \(cellCount) cell scenes")
// 打印输出 "6 mansion scenes; 2 cell scenes"
字符串的 Unicode 表示形式(Unicode Representations of Strings)
- UTF-8 代码单元集合 (利用字符串的utf8属性进行访问)
- UTF-16 代码单元集合 (利用字符串的utf16属性进行访问)
- 21位的 Unicode 标量值集合,也就是字符串的 UTF-32 编码格式 (利用字符串的unicodeScalars属性进行访问)
let dogString = "Dog‼🐶"
for codeUnit in dogString.utf8 {
print("\(codeUnit) ", terminator: "")
}
print("")
// 68 111 103 226 128 188 240 159 144 182
for codeUnit in dogString.utf16 {
print("\(codeUnit) ", terminator: "")
}
print("")
// 68 111 103 8252 55357 56374
for scalar in dogString.unicodeScalars {
print("\(scalar.value) ", terminator: "")
}
print("")
// 68 111 103 8252 128054
for scalar in dogString.unicodeScalars {
print("\(scalar) ")
}
// D
// o
// g
// ‼
// 🐶