【译】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. jq weui 滚动加载的坑

    1.一般情况下使用官网给个demo就可以了,如下: var loading = false; //状态标记 $(document.body).infinite().on("infinite& ...

  2. javaScript中for-in语句

    for-in语句是一种精准的迭代语句,用来枚举对象的属性 实例: <!DOCTYPE html><html><head> <title>For-In S ...

  3. spark sql 的metastore 对接 postgresql

    本教程记录 spark 1.3.1 版本的thriftserver 的metastore 对接 postgresql postgresql 的编译,参考:http://www.cnblogs.com/ ...

  4. ADO学途 four day 数据库左右连接

    数据库的多表操作 数据库用于存放用户数据,用户数据库的数据又会有不同表来存放不同类型的数据,这这是就会产生多 张表来满足需求.列如,部门表有市场部,技术部,行政部等.,子表就有员工具体信息表用来存放员 ...

  5. Python及bs4、lxml、numpy模块包的安装

    http://blog.csdn.net/tiantiancsdn/article/details/51046490(转载) Python及bs4.lxml.numpy模块包的安装 Python 的安 ...

  6. DRF教程5-API接口文档和接口测试

    配置 配置好,就可以访问web页面 pip install coreapi #安装依赖 from rest_framework.documentation import include_docs_ur ...

  7. Codeforces Round #533(Div. 2) A.Salem and Sticks

    链接:https://codeforces.com/contest/1105/problem/A 题意: 给n个数,找到一个数t使i(1-n)∑|ai-t| 最小. ai-t 差距1 以内都满足 思路 ...

  8. 安卓新的联网方式 Volley的使用(2)

    如果使用volley 获取 网络图片 最好还是用 Volley 提供的NetworkImageView类,  可以很轻松的 完成工作, 而且他可以设置缓存, lru 和 sd卡的缓存.一些都封装好了. ...

  9. mouseover等闪烁问题

    在使用mouseover等鼠标事件时如移动上去灰色的遮罩层高度从0到100% 在操作中发现鼠标一直在图里面但遮罩会一直变化,我感觉应该是遮罩层出现后导致鼠标离开了底层图片所以会一直变化.想起之前用的 ...

  10. [转]Formatting the detail section to display multiple columns (水晶报表 rpt 一页多列)

    本文转自:http://www.bofocus.com/formatting-the-detail-section-to-display-multiple-columns/ Format the de ...