Swift从零开始 - 字符串

72 阅读5分钟

字符串的初始化

字面量

Swift字面量是 固定顺序的文本字符。Swift会将此推断为String类型。

单行字面量

可以通过双引号("") 包裹的形式创建

var emptyStr = ""

var str = "text"

多行字面量

可以通过三引号(""" """) 包裹的形式创建。
在多行字面量内 使用 换行符(回车键), 则是按照换行输出,如果仅想易读而实际不换行, 可以使用反斜杠 \ 分隔。

var linesStr = """
               one line,
               two lines
               """
print(linesStr)    
//             one line,
               two lines
               
var linesStr = """
               one line,\
               two lines
               """
print(linesStr)    
//             one line two lines               

初始化语法器

也可以通过 String() 初始化器语法创建

var emptyStr = String()

let catCharacter : [Character] = ["C","a","t","!","🐱"]
let cat = String(catCharacter) // Cat!🐱

特殊字符

转义特殊字符

\0 : 空字符, \\ : 反斜杠, \t :水平制表符, \n: 换行符, \r: 回车符, \": 双引号, \':单引号 等等

Unicode标量

\u{n}: n为 1-8 位的 16进制数字,其值为合法的Unicode值

let sparklingHeart = "\u{1F496}" //💘

多行字面量的引号

在多行字面量里, 如果是双引号 "" 无需特殊转义,即可显示, 如果是三引号 """, 则至少需要转义一个引号。

Raw String

扩展字符串分隔符: 将字符串放在 " 内, 并由 # 在最外层包裹。如果字符串内部有 #, 则首尾的 # 个数需要增多一个,首尾的 # 个数可以多个,但是需首位个数一致。

在字面量里 放置 扩展分隔符, 可以让其包含的特殊字符不生效。

let str = #"Line1 \nLine2"# 
print(str) // Line1 \nLine2, \n不生效

如果需要让特殊字符生效, 可以在特殊字符之前加上 与 首尾相同个数的 # 来实现

let str = #"Line1 \#nLine2"# 
print(str) 
// Line1
   Line2
   
let str = ###"Line1 \###nLine2"### 
print(str) 
// Line1
   Line2

字符串的常见操作

字符串的可变性表示

不同于OC的 不可变用NSString表示, 可变用NSMutableString表示。
Swift中,是否可变 还是通过 letvar 表示, let表示不可变, var表示可变, Swift的方式更加统一。

let str = "abc"
str += "def" // error

var str = "abc"
str += "def" // abcdef

字符串是值类型

不同于OC的字符串是对象类型,Swift中的字符串是值类型。

所以 String值,在传递给函数的时候会被复制过去的,是两份不同的副本。

值得注意的是, Swift编译器优化了字符串使用的资源, 只有在确实需要的时候才会进行实际上的拷贝。

var str = "abc"   // abc
var str1 = str    // abc
print(str == str1) // true
str += "def"       // abcdef
print(str == str1) //false
print(str)        // abcdef
print(str1)       // abc

操作字符

String中的每一个字符都是 Character 类型,可以使用如下方式操作字符。

  • for-in循环遍历String中的每一个独立的 Character。
let str = "hello"

for c in str {
print(c) // "h" "e" "l" "l" "o"
  • 使用索引操作字符
    每一个String值都有相关的索引类型 : String.index, 它相当于每个Character在字符串中的位置。
    startIndex 属性用来访问 String 中的第一个字符的位置, endIndex 用来访问String中的最后一个字符位置, endIndex 并不是字符串下标脚本的合法实际参数, 如果String为空, 则startIndexendIndex 相等.
let str = "hello"
str[tr.startIndex] // "h"

str[1]  //error!!!  index 实际类型是struct 而不是int

使用index(before:)index(after:) 方法来访问给定索引的前后。
使用index(_:offsetBy:) 方法来访问给定索引 的指定偏移索引
使用indices 属性来访问字符串中每个字符的索引

let str = "hello"
str[str.index(before:str.endIndex)]  // "o"
str[str.index(after:str.startIndex)] // "e"
let index = str.index(str.startIndex, offsetBy:3)
str[index]                           // "l"

字符串拼接

  • 使用加运算符 + ,创建新字符串。
  • 使用 +=, 在原字符串后面拼接新串。
  • 使用String类型的 append() 方法来给原字符串末尾追加 Character 值。
var str = "hello,"
var str1 = "world"
var newStr = str + str1
print(str)              // "hello,"
print(newStr)           // "hello,world"

var str += str1 
print(str)             // "hello,world"

字符串插值

字符串插值是一种从混合常量,变量,字面量和表达式的字符串字面量构造新String值的方法。
它类似于OC中 NSStringstringWithFormat方法
每一个插入到字符串字面量的元素都要被一对小括号包裹,并使用反斜杠前缀: \()

let num = 3
let str = "times"
let message = "\(num) \(str) 2.5 is \(Double(num) * 2.5)" // 3 times 2.5 is 7.5

可以在 Raw String 中创建一个包含在其他情况下会被当作字符串插值的字符。
要在使用 Raw String 的字符串中使用 字符串插值, 仍然需要在反斜杠 \ 后 ,使用 匹配首尾 # 数量的 #。

print(#"\(3) \("times") 2.5 is \(Double(3) * 2.5"#) 
// \\(3) \\("times") 2.5 is \\(3 * 2.5)\n
print(#"\#(3) \#("times") 2.5 is \#(Double(3) * 2.5"#) 
// 3 times 2.5 is 7.5

插入

  • 插入字符:使用insert(:_at:)方法
  • 插入另一个字符串的内容到指定的索引, 使用insert(contentsOf:at:)方法
var str = "hello"
str.insert("!" at: str.endIndex)   // "hello!\n"

str.insert(contentsOf:" world", at: str.index(befor:str.endIndex)) // "hello world!\n"

删除

  • 移除字符: 使用 remove(at:) 方法
  • 移除特定范围内的字符串, 使用 removeSubrange(_:) 方法
var str = "hello world!"
str.remove(at: str.index(before:str.endIndex))  // "hello world\n"

let range = str.index(str.endIndex, offsetBy: -6..<str.endIndex)
str.removeSubrange:(range)                      // "hello\n"

子字符串

在Swift中, 使用下标或者类似 prefix(_:) 方法得到的子字符串 是Substring类型
Substring 拥有 String 的大部分方法, 也可以转成 String

let str = "hello, world!"
let index = str.index(of: ",") ?? str.endIndex
let begin = str[..<index]
let newStr = String(begin) 

为什么Swift用Substring表示子字符串:
主要为性能考虑:

  • 子字符串可以重用原字符串的一部分内存
  • 修改字符串或者子字符串之前都不需要花费拷贝内存的代价
  • String和Substring都遵循 StringProtocol 协议, 也就是说它基本上能很方便地兼容所有接受 StringProtocol 值的字符串操作函数。

Screenshot 2023-12-04 at 23.17.03.png

字符串比较

  • 使用 == 或 != 来比较字符串和字符的相等性
  • 使用 hasPrefix(_:) 方法 判断前缀相等性
  • 使用 hasSuffix(_:) 方法 判断后缀相等性
let str = "hello"
let str1 = "hello, world!"
print(str == str1)  //false
print(str.hasPrefix("hello")) //true
print(str1.hasSuffix("world!")) //true