Swift 的标准库功能丰富,但通过导入外部库和框架,你还能用上许多额外的功能。 这些模块可能直接来自 Swift 项目(例如 Swift Argument Parser),来自 Apple 平台框架(例如 Foundation 和 Network Framework),也可能来自第三方开源库(例如 SwiftyBeaver)。
像 Foundation 这样的核心模块(Swift 中使用最广泛的库之一)随 Swift 工具链一起提供。 第三方库必须先添加到项目配置中(例如使用 Swift Package Manager),然后才能导入。
导入模块的方法是写下 import 关键字,后面跟上模块名。
比如,只要在程序中加上下面这行,就能导入 Foundation。
import Foundation
导入模块后,它的类型、方法和函数就可以在你的代码中使用了。
例如,导入 Foundation 会为 String 扩展出 components(separatedBy:) 等实用的工具方法。
按照惯例,import 语句放在 Swift 文件的顶部,这样任何人阅读代码时都能立刻看到依赖项。
String 中的单个字符可以用数组使用的那种下标方式访问。
但字符串使用的下标_不是_整数,不能直接拿来运算。
它们必须基于某个已知的下标计算出来,比如 startIndex,它指向非空字符串中第一个字符的位置,计算时要用 String 和 NSString 库提供的方法(导入 Foundation 模块后,Swift 中的字符串就能使用 NSString 的所有属性和方法)。
例如,给定下面这个字符串:
let csv = "apple,pear,peach,orange,cherry,lime,goosberry"
不能写 csv[21] 来取得 “orange” 中的 “g”,而必须计算出一个 String.Index 类型的值,再把这个下标传进去。
注意,这些下标本身并不是给人直接读取的。
它们被称为_不透明下标_,人类无需知道里面是什么。
let index = csv.index(csv.startIndex, offsetBy: 21)
csv[index]
// "g"
print(index)
// prints Index(_rawBits: 1376513)
但要注意,如果偏移量不是有效的下标,也就是说,如果它得到的位置在 startIndex 之前或 endIndex 之后,这个操作就会报错,导致程序崩溃。
要避免这个问题,可以指定一个限制下标。
这时返回的是一个可选下标,对于本来无效的下标会返回 nil。
let tooFar = csv.index(csv.startIndex, offsetBy: 200)
// error: Execution was interrupted, reason: EXC_BAD_INSTRUCTION (code=EXC_I386_INVOP, subcode=0x0).
let tooFarButSafe = csv.index(csv.startIndex, offsetBy: 200, limitedBy: csv.endIndex)
// nil
此外,下标不能在字符串之间共享。
例如,用上面算出的 “orange” 中 “g” 的 index 去索引字符串 fam = "This is my family: 👨👩👦👦, this is our dog: 🐶, this is our cat: 🐱!",也就是 fam[index],会让程序崩溃。
造成这一切的原因有很多,但归根结底是 “Unicode 很棘手”。
一般来说,如果你需要随机访问单个字符,最好改用别的数据结构,比如 Array<Character>。
Swift 提供了 first 和 last 方法,用来获取字符串的第一个和最后一个字符。
这两个方法返回可选字符,所以如果字符串为空,会返回 nil。
let str = "Hello, world!"
print(str.first) // Prints Optional("H")
print(str.last) // Prints Optional("!")
你也可以用 prefix 和 suffix 方法获取字符串的子串。
这两个方法接收一个整数作为实参,返回包含字符串前 n 个或后 n 个字符的子串。
let str = "Hello, world!"
print(str.prefix(5)) // Prints "Hello"
print(str.suffix(6)) // Prints "world!"
处理文本是编程中常见的任务。 Swift 以及 Foundation 框架提供了许多方便的方法和属性,用来检查、转换和操作字符串。
components(separatedBy:) 拆分字符串要根据分隔符把字符串拆分成子串数组,请使用 components(separatedBy:)(需要导入 Foundation):
import Foundation
let sentence = "Hello, world!"
let words = sentence.components(separatedBy: " ")
print(words) // Prints ["Hello,", "world!"]
hasPrefix(_:) 和 hasSuffix(_:) 检查前缀和后缀要检查字符串是否以特定的字符序列开头或结尾,请使用 hasPrefix(_:) 和 hasSuffix(_:):
let greeting = "Hello, world!"
print(greeting.hasPrefix("Hello")) // Prints true
print(greeting.hasSuffix("world!")) // Prints true
你可以用下面这些标准方法和属性来转换字符串的大小写:
lowercased():返回字符串的小写副本。uppercased():返回字符串的大写副本。capitalized:返回每个单词首字母大写的副本(来自 Foundation)。let greeting = "hello, world!"
print(greeting.lowercased()) // Prints "hello, world!"
print(greeting.uppercased()) // Prints "HELLO, WORLD!"
print(greeting.capitalized) // Prints "Hello, World!"
replacingOccurrences(of:with:) 替换子串要把目标子串的所有出现都替换成另一个字符串,请使用 replacingOccurrences(of:with:)(来自 Foundation):
let greeting = "Hello, world!"
let updated = greeting.replacingOccurrences(of: "world", with: "Swift")
print(updated) // Prints "Hello, Swift!"
joined(separator:) 连接字符串joined(separator:) 方法属于字符串集合,例如 [String]。
它用一个分隔符把各个元素连接成单个字符串:
let words = ["Hello", "world"]
let sentence = words.joined(separator: ", ")
print(sentence) // Prints "Hello, world"
镇上新开了一家诗歌俱乐部,你正想着要不要去。 因为以前出过一些事,俱乐部有一套非常特别的进门规定,你得先掌握它,才能尝试入场。
诗歌俱乐部有两扇门,都有人把守。 想进去,你得破解出当天的密码:
你要做的第一件事,是把这首诗拆分成单独的行。 守卫会念出一首诗,你要把它拆成若干行。
实现函数splitOnNewlines,它接收一个字符串,以换行符为分隔符,把它拆分成一个字符串数组。
函数应返回一个字符串数组,其中每个字符串都是诗中的一行。
splitOnNewlines("Hello.\nHow are you?\n\nI'm doing fine.")
// returns ["Hello." ,"How are you?", "", "I'm doing fine"].
_代替。比如,他们最喜欢的作家之一是 Michael Lockwood,他写过下面这首_藏头诗_,也就是说每句的首字母能拼成一个单词:
Stands so high
Huge hooves too
Impatiently waits for
Reins and harness
Eager to leave
守卫念出这首诗时,你要把它拆分成单独的行,然后回答每一行的首字母,也就是["S", "H", "I", "R", "E"]。
然后守卫会把你回答的字母数组所拼成的单词给你,让你把它变成首字母大写的单词形式。
最后你返回的密码是"SHIRE",你就能进去了。
实现函数frontDoorPassword,它接收一个表示这首诗的字符串。
函数应返回你要告诉守卫的密码。
frontDoorPassword("Stands so high\nHuge hooves too\nImpatiently waits for\nReins and harness\nEager to leave")
// returns "SHIRE"
在俱乐部后面,你能见到最著名的诗人,那里就像 VIP 专区。 因为不是谁都能进,后门的流程要绕一些。
", please"。比如,前面提到的那首诗也是_藏尾诗_,也就是说每句的末字母能拼成一个单词:
Stands so high
Huge hooves too
Impatiently waits for
Reins and harness
Eager to leave
守卫念出这首诗时,你要把它拆分成单独的行,去掉末尾的空格,然后回答每一行的首字母,也就是["h", "o", "r", "s", "e"]。
然后守卫会把你回答的字母数组所拼成的单词给你,让你把它变成首字母大写的单词形式,并加上", please"。
最后你返回的密码是"horse, please",你就能进去了。
实现函数backDoorPassword,它接收一个表示这首诗的字符串。
函数应返回你要告诉守卫的密码。
backDoorPassword("Stands so high\nHuge hooves too\nImpatiently waits for\nReins and harness\nEager to leave")
// returns "horse, please"
俱乐部后室里还有一扇门,通向密室,只有最顶尖的诗人才能进入。
"!"。比如,前面提到的那首诗稍作修改后,就符合这个规律:
Stands so high
Huge hooves too
Impatiently waits for
Rider with harness
Eager to leave
守卫念出这首诗时,你要把它拆分成单独的行,去掉末尾的空格,然后回答每一行的第 ith 个字母,也就是 ["S", "u", "p", "e", "r"]。
然后守卫会把你回答的字母数组所拼成的单词给你,让你把它变成大写形式,并加上"!"。
最后你返回的密码是SUPER!,你就能进去了。
实现函数secretRoomPassword,它接收一个表示这首诗的字符串。
函数应返回你要告诉守卫的密码。
secretRoomPassword("Stands so high\nHuge hooves too\nImpatiently waits for\nRider with harness\nEager to leave")
// returns "SUPER!"