Swift4字符和字符串
只列出与C语言不同或者在C中不常见的用法
String
类型可以作为Character
类型的数组来访问
字符串的创建和修改语法非常轻量易读,使用与 C 类似的字符串字面量语法。
字符串串联只需要使用 +运算符即可。
字符串字面量
let someString = "some string literal value" //使用字符串字面量初始化
上述例子使用了字符串字面量初始化,所以someString被推测为String
多行字符串使用"""
初始化(类似Python)
let quotation = """
The White Rabbit put on his spectacles. "Where shall I begin,
please your Majesty?" he asked.
"Begin at the beginning," the King said gravely, "and go on
till you come to the end; then stop."
"""
在这个多行格式中,字符串字面量包含了双引号包括的所有行。字符串起始于三个双引号( """ )之后的第一行,结束于三个双引号( """ )之前的一行,也就是说双引号不会开始或结束带有换行。下面两个是一样的
let singleLineString = "These are the same."
let multilineString = """
These are the same.
"""
初始化字符串
两种方法
var emptyString = ""
var anotherEmptyString = String()
字符串是值类型
重要,不同于Objective-C和C,在Swift中字符串是值类型,如果你创建了一个新的 String值, String值在传递给方法或者函数的时候会被复制过去,还有赋值给常量或者变量的时候也是一样。每一次赋值和传递,现存的 String值都会被复制一次,传递走的是拷贝而不是原本。
另一方面,Swift 编译器优化了字符串使用的资源,实际上拷贝只会在确实需要的时候才进行。这意味着当你把字符串当做值类型来操作的时候总是能够有用很棒的性能。
这点和Objective-C不一样,Objective-C中NSString是指针类型。
操作字符串
可以使用for-in
操作遍历String中的每个Character
连接操作
-
使用
+
连接字符串 -
使用append连接
字符串插值
也就是其他语言中的格式化输出,字符串插值是一种从混合常量、变量、字面量和表达式的字符串字面量构造新 String值的方法。每一个你插入到字符串字面量的元素都要被一对圆括号包裹,然后使用反斜杠前缀:
let multiplier = 3
let message = "\(multiplier) times 2.5 is \(Double(multiplier) * 2.5)"
// message is "3 times 2.5 is 7.5"
unicode
字符串字面量能包含以下特殊字符:
- 转义特殊字符 \0 (空字符), \ (反斜杠), \t (水平制表符), \n (换行符), \r(回车符), " (双引号) 以及 ' (单引号);
- 任意的 Unicode 标量,写作 \u{n},里边的 n是一个 1-8 个与合法 Unicode 码位相等的16进制数字。
下边的代码展示了这些特殊字符的四个栗子。 wiseWords常量包含了两个转义双引号字符。 dollarSign, blackHeart和 sparklingHeart常量展示了 Unicode 标量格式:
let wiseWords = "\"Imagination is more important than knowledge\" - Einstein"
// "Imagination is more important than knowledge" - Einstein
let blackHeart = "\u{2665}" // ♥, Unicode scalar U+2665
字符
- 可以单独创建字符
let exclamationMark:Character = "!"
- 字符数组和字符串的转换
let catCharacter:[Character] = ["c","a","t"]
let catString = String(catCharacter)
print(catString)
可见,字符串并不等于字符数组,实际上,字符串在Swift中是以双向链表的形式存储的
字符串索引
Character
在String
中是一个双向链表的结构,所以String
不能通过整数下标来索引
String的索引要使用String.Index
对象来索引,有startIndex
和endIndex
等,可以通过偏移量访问其他部分
let greeting = "Guten Tag!"
greeting[greeting.startIndex]
// G
greeting[greeting.index(before: greeting.endIndex)]
// !
greeting[greeting.index(after: greeting.startIndex)]
// u
let index = greeting.index(greeting.startIndex, offsetBy: 7)
greeting[index]
// a
字符串下标不能越界,否则会报错
字符串遍历
let greeting = "Hello"
for index in greeting.indices{
print("\(greeting[index])",terminator:" ") //terminator默认为换行
}
// 输出: H e l l o
插入和删除
- 插入
var welcome = "hello"
welcome.insert("!", at: welcome.endIndex)
// welcome now equals "hello!"
welcome.insert(contentsOf:" there".characters, at: welcome.index(before: welcome.endIndex))
// welcome now equals "hello there!"
- 删除
welcome.remove(at: welcome.index(before: welcome.endIndex))
// welcome now equals "hello there"
let range = welcome.index(welcome.endIndex, offsetBy: -6)..<welcome.endIndex
welcome.removeSubrange(range)
// welcome now equals "hello"
子串
重要:当需要使用一个字符串生成子串的时候,是生成了一个SubString
的实例,而不是新的一个字符串,大部分String
操作可以直接用在SubString
上面,可以直接使用操作字符串的方法操作子串。
但是,子串只是对原字符串的暂时操作才使用,如果要将子串结果保存更长时间,需要将子串转化为字符串。
let greeting = "Hello,world!"
let index = greeting.index(of:",") ?? greeting.endIndex
let beginning = greeting[..<index]
// beginning是"Hello"
// 将子串转换为字符串
let newString = String(begninning)
像字符串一样,子串也有一块内存空间来存储。不同的是,作为性能优化,子串可以重用原始字符串的内存空间(字符串也有类似的优化,即如果两个字符串共享内存地址,则它们相等)。这样的性能优化意味着如果你不改变字符串内容,在使用字符串或者子串的时候不用担心性能。就像上面说的,子串不适合长时间的存储--因为它其实是重用了原字符串的内存,当原字符串在内存中存在的时候,子串才可以用。
在上述的例子中,greeting
是一个字符串,所以它有一块内存空间来存储字符。而beginning
是子串,所以它重用了greeting
的内存空间。而与之不同的,newString
是字符串,所以newString
开辟了新的内存空间来存储。
字符串比较
-
如果两个字符串或者子串内容相同,则两个字符串相同,直接使用
==
和!=
比较就可以。 -
前缀和后缀的比较
使用hasPrefix(_:)
和hasSuffix(_:)
方法