【译】Swift 字符串速查表

2015-12-18 10:32 编辑: suiling 分类:Swift 来源:CocoaChina翻译活动

10 5585


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 字符串速查表的更多相关文章

  1. Java, C#, Swift语法对比速查表

    原文:Java, C#, Swift语法对比速查表   Java 8 C# 6 Swift 变量 类型 变量名; 类型 变量名; var 变量名 : 类型; 变量(类型推断) N/A var 变量名= ...

  2. .htaccess下Flags速查表

    Flags是可选参数,当有多个标志同时出现时,彼此间以逗号分隔. 速查表: RewirteRule 标记 含义 描述 R Redirect 发出一个HTTP重定向 F Forbidden 禁止对URL ...

  3. OpenStack 命令行速查表

    OpenStack 命令行速查表   updated: 2017-07-18 08:53 Contents 认证 (keystone) 镜像(glance) 计算 (nova) 实例的暂停.挂起.停止 ...

  4. 【转】shell速查表

    shell速查表 转自:https://www.jianshu.com/p/a98a334bfb25 1. 变量 #!/bin/bash msg="hello world" ech ...

  5. GNU Emacs命令速查表

    GNU Emacs命令速查表 第一章  Emacs的基本概念 表1-1:Emacs编辑器的主模式 模式 功能 基本模式(fundamental mode) 默认模式,无特殊行为 文本模式(text m ...

  6. vim基本命令速查表

    来源:https://github.com/skywind3000/awesome-cheatsheets/blob/master/editors/vim.txt ################## ...

  7. bash基本命令速查表

    来源:https://github.com/skywind3000/awesome-cheatsheets/blob/master/languages/bash.sh ################ ...

  8. 【转】正则表达式速查表(http://www.jb51.net/shouce/jquery1.82/regexp.html)

    正则表达式速查表 字符 描述 \ 将下一个字符标记为一个特殊字符.或一个原义字符.或一个向后引用.或一个八进制转义符.例如,“n”匹配字符“n”.“\n”匹配一个换行符.串行“\\”匹配“\”而“\( ...

  9. Bash中文速查表

    最好用的中文速查表(Cheatsheet) 来源:https://github.com/skywind3000/awesome-cheatsheets 感谢网友们的贡献! ############## ...

随机推荐

  1. java string(转)

    初探Java字符串 优化变成了忧患:String.split引发的“内存泄露” String是java中的无处不在的类,使用也很简单.初学java,就已经有字符串是不可变的盖棺定论,解释通常是:它是f ...

  2. day03 内部类

  3. shell学习(4)- awk

    简介 awk是一个强大的文本分析工具,相对于grep的查找,sed的编辑,awk在其对数据分析并生成报告时,显得尤为强大.简单来说awk就是把文件逐行的读入,以空格为默认分隔符将每行切片,切开的部分再 ...

  4. 测试 | 代码覆盖测试工具 | Eclemma

    安装: 打开eclipse,点击Help菜单下的Install New Software 在弹出的对话框中,点击Add 输入Name,如EclEmma 输入Location: http://updat ...

  5. nginx,tomcat,apache三者分别用来做什么,有何区别

    1. Nginx和tomcat的区别 nginx常用做静态内容服务和代理服务器,直接外来请求转发给后面的应用服务器(tomcat,Django等),tomcat更多用来做一个应用容器,让java we ...

  6. monxin cms 任意文件删除漏洞

    \program\diypage\receive\edit.php首先看到一个unlink($path);本来应该先看sql语句的,但知道是任意文件删除先跳过删除语句,看看$path怎么传入的倒推上去 ...

  7. 洛谷1941(dp)

    常规的dp,当前有值且碰不到管子就转移,可以连跳的操作我就加了一维表示当前是不是连跳过来的.第二问前缀和即可得(不对啊边走边记录就行了吧我冗了Orz). #include <cstdio> ...

  8. oracle把一个表的数据复制到另一个表中

    http://blog.csdn.net/my_name_nb/article/details/64128015 ........................ 1. 新增一个表,通过另一个表的结构 ...

  9. foreach循环与迭代器循环 删除插入元素的区别

     (1)仅对其遍历而不修改容器大小时,只使用foreach循环 (2)需要边遍历边修改容器大小时(插入删除元素),只使用迭代器循环 import java.util.HashMap;import ja ...

  10. django-Haystack库

    本文参考自Haystack官方文档:https://django-haystack.readthedocs.io/en/master/tutorial.html#configuration 简介 Ha ...