Swift 的字符串 API 似乎让人难以习惯。此外,每次 Swift 与其标准库版本更新的时候,字符串的 API 也时不时会发生改变。你在 Stack Overflow 上寻找到的 Swift 1.2 解决方案往往不能在 Swift 2 上按照预期(甚至完全不能)使用。虽然从好的方面来看,我发现苹果的官方文档是非常有用的(参见本文底部的链接),但是出于备查的目的以及为了帮助仍挣扎于其中的人们,在此我仍旧了列出一系列的 String 代码片段:
(Gist 和我 Github 仓库中的 Playground 都已提供)
字符串初始化
创建一个字符串对象有无数种方式可以使用,包括字面量、从其他 Swift 类型转换、Unicode等等。
1
2
3
4
5
6
7
8
9
10
11
|
var emptyString = "" // 空字符串
var stillEmpty = String() // 另一种空字符串的形式
let helloWorld = "Hello World!" // 字符串字面量
let a = String( true ) // 由布尔值转换为:"true"
let b: Character = "A" // 显式创建一个字符类型
let c = String(b) // 从字符 "A" 转换
let d = String(3.14) // 从 Double 类型转换为 "3.14"
let e = String(1000) // 从 Int 类型转换为 "1000"
let f = "Result = \(d)" // 字符串插值 "Result = 3.14"
let g = "\u{2126}" // Unicode 字符,欧米伽符号 Ω
let h = String(count:3, repeatedValue:b) // 重复字符组成的字符串 "AAA"
|
字符串是值类型
字符串是值类型(Value Type),当用其赋值或者函数传参的时候它会被拷贝(copied)。所拷贝的值在修改的时候是懒加载的(lazy)。
1
2
3
4
|
var aString = "Hello"
var bString = aString
bString += " World!" // "Hello World!"
print( "\(aString)" ) // "Hello\n"
|
字符串检测(空值、等值以及次序)
检测一个字符串是否为空:
1
|
emptyString.isEmpty // true
|
Swift 是支持 Unicode 编码的,因此相等运算符("==")将会判断 Unicode 的范式是否等价(canonical equivalence)。这意味着对于两个字符串来说,如果拥有相同的语义(linguistic meaning)和表现形式的话,即使它们由不同 Unicode 标量(scalar)组成,那么也认为这两个字符串相等:
1
2
3
4
5
6
|
let spain = "Espa?a"
let tilde = "\u{303}"
let country = "Espan" + "\(tilde)" + "a"
if country == spain {
print( "满足匹配!" ) // "满足匹配!\n"
} |
比较次序的话:
1
2
3
|
if "aaa" < "bbb" {
print( "aaa" )
} |
前缀/后缀检测
检测一个字符串是否拥有某个前缀或者后缀:
1
2
3
|
let line = "0001 这里放上一些测试数据 %%%%"
line.hasPrefix( "0001" ) // true
line.hasSuffix( "%%%%" ) // true
|
大小写互相转换
顾名思义:
1
2
3
|
let mixedCase = "AbcDef"
let upper = mixedCase.uppercaseString // "ABCDEF"
let lower = mixedCase.lowercaseString // "abcdef"
|
字符集合
字符串并不是某种编码的字符集合(collection views),但是它可以通过相应的属性为不同的编码形式提供所对应的字符集合。
1
2
3
4
|
country.characters // characters
country.unicodeScalars // Unicode scalar 21-bit codes
country.utf16 // UTF-16 编码
country.utf8 // UTF-8 编码
|
字符总数
字符串并没有一个直接的属性用以返回其包含的字符总数,因为字符总数只对特定的编码形式来说才有意义。因此,字符总数需要通过不同编码的字符集合来访问:
1
2
3
4
5
|
// spain = Espa?a print( "\(spain.characters.count)" ) // 6
print( "\(spain.unicodeScalars.count)" ) // 6
print( "\(spain.utf16.count)" ) // 6
print( "\(spain.utf8.count)" ) // 7
|
使用索引来访问字符集合
每个字符集合都拥有“索引”,可以通过它来访问整个集合中的元素。这或许是在使用字符串过程中碰到的最大难点之一了。你不能使用下标语法来访问字符串中的任意元素(比如说string[5])。
要遍历某个集合中的所有元素的时候(从现在开始我都将使用 characters 集合),可以通过 for...in 循环来进行:
1
2
3
4
|
var sentence = "Never odd or even"
for character in sentence.characters {
print(character)
} |
每个集合都有两个实例属性,你可以在集合中使用它们来进行索引,就如同下标语法哪样:
-
startIndex:返回首个元素的位置,如果为空,那么和 endIndex 的值相同。
-
endIndex:返回字符串逾尾(past the end)的位置。
注意到如果使用 endIndex 的话,就意味着你不能直接将其作为下标来进行使用,因为这会导致越界。
1
2
3
|
let cafe = "café"
cafe.startIndex // 0
cafe.endIndex // 4 - 最后一个字符之后的位置
|
当通过以下几种方法进行字符串修改的时候,startIndex 和 endIndex 就变得极其有用:
-
successor():获取下一个元素
-
predecessor():获取上一个元素
-
advancedBy(n):向前或者向后跳 n 个元素
下面是一些用例,注意到如果必要的话你可以将操作串联起来:
1
2
3
4
5
6
7
|
cafe[cafe.startIndex] // "c"
cafe[cafe.startIndex.successor()] // "a"
cafe[cafe.startIndex.successor().successor()] // "f"
// 注意到 cafe[endIndex] 会引发运行时错误 cafe[cafe.endIndex.predecessor()] // "é"
cafe[cafe.startIndex.advancedBy(2)] // "f"
|
Indices 属性将返回字符串中所有元素的范围,这在遍历集合的时候很有用:
1
2
3
|
for index in cafe.characters.indices {
print(cafe[index])
} |
你无法使用某个字符串中的索引来访问另一个字符串。你可以通过 distanceTo 方法将索引转换为整数值:
1
2
3
4
5
|
let word1 = "ABCDEF"
let word2 = "012345"
let indexC = word1.startIndex.advancedBy(2) let distance = word1.startIndex.distanceTo(indexC) // 2
let digit = word2[word2.startIndex.advancedBy(distance)] // "2"
|
范围的使用
要检出字符串集合中某个范围内的元素的话,可以使用范围。范围可以通过 start 和 end 索引来完成创建:
1
2
3
4
|
let fqdn = "useyourloaf.com"
let rangeOfTLD = Range(start: fqdn.endIndex.advancedBy(-3), end: fqdn.endIndex)
let tld = fqdn[rangeOfTLD] // "com"
|
使用 "..." 或者 "..<" 运算符可以快速完成范围的创建:
通过索引或者范围来截取字符串
要通过索引或者范围来截取字符串的话,有许多方法:
获取前缀或者后缀
如果你需要得到或者抛弃字符串前面或者后面的某些元素的话,可以:
1
2
3
4
5
6
7
8
9
10
11
12
|
let digits = "0123456789"
let tail = String(digits.characters.dropFirst()) // "123456789"
let less = String(digits.characters.dropFirst(3)) // "23456789"
let head = String(digits.characters.dropLast(3)) // "0123456"
let prefix = String(digits.characters.prefix(2)) // "01"
let suffix = String(digits.characters.suffix(2)) // "89"
let index4 = digits.startIndex.advancedBy(4) let thru4 = String(digits.characters.prefixThrough(index4)) // "01234"
let upTo4 = String(digits.characters.prefixUpTo(index4)) // "0123"
let from4 = String(digits.characters.suffixFrom(index4)) // "456789"
|
插入或删除
要在指定位置插入字符的话,可以通过索引:
1
2
3
|
var stars = "******"
stars.insert( "X" , atIndex: stars.startIndex.advancedBy(3))
// "***X***" |
要在索引出插入字符串的话,那么需要将字符串转换为字符集:
1
2
|
stars.insertContentsOf( "YZ" .characters, at: stars.endIndex.advancedBy(-3))
// "***XYZ***" |
范围替换
要替换一个范围的字符串内容的话:
添加元素
可以通过“+”运算符将字符串相互连接起来,也可以使用 appendContentsOf 方法:
1
2
3
|
var message = "Welcome"
message += " Tim" // "Welcome Tim"
message.appendContentsOf( "!!!" ) // "Welcome Tim!!!
|
移除或者返回指定索引的元素
从一个字符串当中移除某个元素,需要注意这个方法将会使该字符串此前所有的任何索引标记(indice)失效:
1
2
3
|
var grades = "ABCDEF"
let ch = grades.removeAtIndex(grades.startIndex) // "A"
print(grades) // "BCDEF"
|
范围移除
移除字符集中某个范围的字符,需要主要的是这个方法同样也会使索引标记失效:
1
2
3
|
var sequences = "ABA BBA ABC"
let midRange = sequences.startIndex.advancedBy(4)...sequences.endIndex.advancedBy(-4) sequences.removeRange(midRange) // "ABA ABC"
|
与 NSString 桥接
String 可以转换为 NSString 从而与 Objective-C 桥接。如果 Swift 标准库没有你所需要的功能的话,那么导入 Foundation 框架,通过 NSString 来访问这些你所需要的方法。
请注意这个桥接方法并不是无损的,因此尽可能使用 Swift 标准库完成大部分功能。
1
2
3
4
|
// 不要忘记导入 Foundation import Foundation let welcome = "hello world!"
welcome.capitalizedString // "Hello World!"
|
检索内含的字符串
使用 NSString 方法的一个例子就是执行内含字符串的检索:
1
2
3
4
5
6
|
let text = "123045780984"
if let rangeOfZero = text.rangeOfString( "0" ,
options: NSStringCompareOptions.BackwardsSearch) {
// 寻找“0”元素,然后获取之后的元素
let suffix = String(text.characters.suffixFrom(rangeOfZero.endIndex)) // "984"
} |
Playgournd
我发现在 Xcode 中通过 Playground 来熟悉 API 是一个非常好的选择。如果你想要抢先体验一下所有这些功能的话,这个文章的 Playground 可以从我的 Github 仓库中下载。
相关推荐
Swift中的函数柯里化,是一种将多参数函数转化为一系列单参数函数的过程,使得函数可以逐步接收参数,并在所有参数提供完整之前返回一个新函数。这种技术源于数学家哈斯凯尔·伽罗瓦(Haskell Curry)的名字,因此被...
let closure = { (index: Int, value: String) in print("Index: \(index), Value: \(value)") } ``` 8. `let` - 声明常量,其值在声明后不可更改。 ```swift let constantValue = 42 ``` 9. `private` / `...
例如,一个函数返回`(Int, (String, Double))`类型的元组,可以直接用`(a, (b, c)) = function()`这样的方式解包,而无需先赋值给一个临时变量再进行逐层解包。 Swift 4.1还增强了对API命名规则的检查。在这一版本...
String(contentsOfFile: scriptPath, encoding: .utf8) context?.evaluateScript(scriptSource) ``` 3. **定义Swift函数供JavaScript调用** 在Swift中,你可以创建一个闭包,然后将其设置为JavaScriptContext的...
3. **循环(for-in, while)**: 重复执行一段代码直到满足某个条件为止。 #### 八、Swift的高级特性 1. **函数(Function)**: 定义可重用的行为单元。 2. **闭包(Closure)**: 匿名函数,可用于定义回调函数等场景。 3....
Swift 提供了多种内置的序列类型,如 Array 和 String,同时也支持自定义序列类型。 5. **Tuple (元组)** 元组是一种将多个值组合在一起的数据结构。它们在 Swift 中被广泛使用,特别是在需要返回多个值的情况时...
1. **Swift基础**:Swift的基础语法包括变量(var和let)、常量、数据类型(Int、Double、String等)、条件语句(if-else)、循环(for-in、while)以及函数(function)的定义和使用。这些都是编写任何程序的基石。...
7. **Function Syntax**:Swift 2中函数参数名和参数标签的分离,使得函数调用更清晰,如`func greet(name: String, greeting: String) -> String`。 8. **Operator Overloading**:可以自定义操作符的行为,使代码...
webView.load(URLRequest(url: URL(string: "https://yourwebpage.com")!)) } // 实现WKScriptMessageHandler协议 func userContentController(_ userContentController: WKUserContentController, didReceive ...
-qiang.png",可能涉及的是Swift的函数(function)和控制流。函数是一段可重用的代码块,可以接收输入(参数)并返回结果。Swift支持多种控制流结构,如if语句用于条件判断,for-in循环用于遍历序列,while循环用于...
2. **字符串(String)**:Swift的字符串是不可变的字符序列,支持Unicode编码。字符串操作包括连接、分割、查找子串等,同时也可与字符数组互相转换。 3. **数组(Array)**和**集合(Set)**:Swift中的数组是...
let script =WKUserScript(source: "function callNative() { window.webkit.messageHandlers.swiftMessageHandler.postMessage('Hello from JavaScript'); }", injectionTime: .atDocumentEnd, forMainFrameOnly: ...
func greet(name: String, greeting: String = "Hello") { print("\(greeting), \(name)!") } // 调用时可省略默认参数 greet(name: "Alice") ``` 函数还可以有可变参数,这些参数允许你在函数内部像数组一样处理...
在Swift编程语言中,工具类(Utility Function)是用来封装常用函数和方法的类或结构体,以便在项目中方便地重用。它们通常包含了各种通用的处理任务,如字符串操作、日期转换、颜色处理等。在"swift-...
- 使用inout参数:在函数中修改值类型参数时,使用inout关键字。 8. **Swift的最新特性**: - 结构化并发(Structured Concurrency):Swift 5.5引入的新特性,用于更安全地管理异步任务。 - 五元组(Tuples):...
private func privateFunction() {} ``` **函数类型的访问控制**: 函数的访问控制与上述相同,可以使用`public`、`internal`或`private`来控制。此外,Swift函数可以没有返回值,仅接受参数,例如`sum()`函数。...
在Swift中,函数扩展(Function Extensions)允许我们为已有的类型添加新的方法,而无需创建子类或遵循协议。这种特性使得我们可以为标准库类型或者第三方库类型添加定制功能,以满足特定需求。例如,我们可以扩展...
- **函数签名**: `public func print(items: Any..., separator: String = " ", terminator: String = "\n")` - 示例: `print("Hello, Swift!")` #### 三、Swift的数据类型 Swift提供了丰富的内置数据类型,以下...
- 数据类型:整型(Int)、浮点型(Double/Float)、字符串(String)、布尔型(Bool) - 枚举(Enum)和结构体(Struct) - 类(Class)、协议(Protocol)和继承 - 函数(Function)和闭包(Closure) - 数组...
1. **Swift基础语法**:包括变量与常量(let和var)、数据类型(Int、Double、String等)、运算符、控制流(if-else、switch、for-in循环)、函数(function)以及类(class)和结构体(struct)的定义与使用。...