美文网首页
#3 字符串和字符(Strings and Characters

#3 字符串和字符(Strings and Characters

作者: JamesSawyer | 来源:发表于2018-08-21 14:46 被阅读49次

    swift相对于JS,

    • 除了 String 类型外,还多一种 Character(C语言中称之为 Char)类型
    • JS中字符串既可以用单引号也可以用双引号来表示字符串,而swift中 String 和 Character 均使用双引号 表示
    • swift中的 String 类型是一种快速,现代化的字符串实现,每一个字符串都是由编码无关的 Unicode 字符组成,并支持访问字符的多种Unicode表达形式
    • Swift 中 String 是 值类型
    • swift 中 String 访问字符的方法对学JS的我看来很操蛋

    1.多行字符

    表示方式是:

    let quotation = """
    这是第一行
    这是第二行
    """;
    

    个人感觉这个就是JS中简陋版的字符串模板,一些示例

    #1 一行写不下, 可以用 '\' 进行换行
    let quotation = """
    这是第一行,\
    这还是第一行的内容,太长了就换一行
    这是第二行
    """;
    
    #2 最底下的 """ 的决定空格数 或者说缩进
    let quotation = """
        这是第一行,
            这是第二行
        这是第3行
        """; // 注意这个前面有4个空格,因为放置位置在此.
    // 等价于
    let quotation = """
    这是第一行,
        这是第二行
    这是第3行
    """;
    
    #3 对 """ 进行转义
    # 如果字符串中正好存在 """ 转义方式有2种: \""" 或者 \"\"\"
    let threeDoubleQuotationMarks = """
    Escaping the first quotation mark \"""
    Escaping all three quotation marks \"\"\"
    """
    
    #4 多个多行字符串结合
    let badStart = """
    one
    two
    """
    let end = """
    three
    """
    print(badStart + end)
    // 打印两行:
    // one
    // twothree
    
    // 如果想要换行 则需要注意这样写
    let goodStart = """
    one
    two
    
    """
    let end = """
    three
    """
    print(goodStart + end)
    // 打印三行:
    // one
    // two
    // three
    

    2.需要转义的字符

    字符串字面量需转义的字符:

    • \0:空字符
    • \\: 反斜杠
    • \t | \n | \r: 水平制表符 | 换行符 | 回车符
    • \": 双引号
    • \': 单引号
    • Unicode 标量: \u{n}, n 是任意1-8位16进制数,且可用的Unicode位码

    示例:

    let wiseWord = "\"想象力比知识更重要\" - 爱因斯坦"
    let dollarSign = "\u{24}" // $ Unicode标量为 U+0024
    let sparklingHeart = "\u{1F496}" // 💖,Unicode 标量 U+1F496
    

    3.字符串插值(string interpolation)

    使用 \(variables || expression) 的形式进行插值操作, 这个等同于JS中的 ${}

    let count = 5
    print("I have \(count) apples") // I have 5 apples
    

    4.字符串的可变性

    这里只提一点,就是swift中用 let 声明的表示常量,这和JS中的 const 一样,但是JS中也有 let 关键词,注意别混淆了,因此在swift中下面做法是错误的:

    let greet = "hello"
    greet += " world" // error 常量字符串不可以被修改
    

    5.Character 类型

    注意有些语言中,这个类型称之为 Char,声明时用单引号,但是swift中Character类型用 双引号 进行声明

    let aChar: Character = "A"
    let charArray: [Character] = ["a", "b", "c"]
    

    另外一般认为String类型是character类型的集合, swift中可以使用 for-in 对字符串进行遍历操作

    let str = "Dog!🐶"
    for character in "Dog!🐶" {
        print(character)
    }
    // D
    // o
    // g
    // !
    // 🐶
    
    // 另外可以通过 type(of:) 方法来判断是否是Character类型
    for char in "Dog!🐶" {
        print(type(of: char))
    }
    // 打印
    // Character (重复5遍)
    

    String 和 Character 类型之间的一些转换和方法

    #1 将Character数组转换为字符串
    # 使用 String 构造器即可
    let cat: [Character] = ["C", "A", "T"]
    let catStr = String(cat) // "CAT"
    
    #2 将Character字符添加到String中
    # 使用 append 方法
    var greet = "hello"
    let exclamationMark = "!"
    greet.append(exclamationMark) // 现在greet变为了 "hello!"
    

    6.Unicode

    个人感觉这部分比较麻烦。

    • swift中的 String 类型是基于 Unicode 标量 建立的。
    • swift中的 Character 类型代表一个可扩展的字形群,一个可扩展的字形群是一个或多个可生成人类刻度的字符Unicode标量的有序排列(好拗口)

    通俗讲一个字符的写法可能由Unicode组成的写法不一样,但是最后结果是一样的:

    let eAcute: Character = "\u{E9}"                         // é
    // 这个相当于对上面 é = e +  ́ 的分解
    let combinedEAcute: Character = "\u{65}\u{301}"          // e 后面加上  ́
    print(eAcute == combinedEAcute) // true
    

    7.字符串的操作

    swift中目前为止感觉语法最难看的部分来了,个人感觉这种设计太复杂了。

    isEmpty 属性 判断字符串是否为空

    let emptyString = ""
    // 或者 let emptyString = String()
    if emptyString.isEmpty {
      print("这是一个空字符")
    }
    // "这是一个空字符"
    

    字符串索引

    因为不同字符可能会占用不同数量的内存空间,所以要知道 Character 的确定位置,就必须从 String 开头遍历每一个 Unicode 标量 直到结尾,因此, swift的字符串不能用整数做索引!!!

    获取字符位置的方法大概有以下几种:

    • startIndex: 获取String的第一个Character的索引, 注意其返回的不是一个Int类型,而是 String.Index 类型
    • endIndex: 获取字符串中最后一个Character的位置索引,注意 endIndex 属性不能作为一个字符串的有效下标!!!
    • index(before: String.Index): 获取某个字符前面的一个位置的索引
    • index(after: String.Index): 获取某个字符后面的一个位置的索引
    • index(_ i: String.Index, offsetBy: Int): 用来获取对应偏移量的索引,例如 someStr.index(someStr.startIndex, offsetBy: 6) 获取开始位置偏移6位的字符
    • indices: 这个属性会创建一个包含全部索引的范围(Range),用来在一个字符串中访问单个字符
    • count: 获取字符的数量

    另外需要注意的是:

    • 如果字符串为空,则 startIndex 等于 endIndex
    #1 获取字符串的长度
    let koala = "Koala 🐨"
    print(koala.count) // 7 , 可以看出 这里 🐨 占一个字符
    
    #2 开始索引
    let greet = "hello world!"
    print(greet[greet.startIndex]) // "h"
    
    #3 endIndex 属性不能作为一个字符串的有效下标!!!
    let greet = "hello world!"
    print(greet[greet.endIndex]) // error  Can't form a Character from an empty String
    
    #4 获取最后一个字符
    # 使用 index(before i: String.Index) 方法
    let greet = "hello world!"
    print(greet[greet.index(before: greet.endIndex)]) // "!"
    
    #5 使用 index(after i: String.Index) 方法 获取第一个字符之后的字符
    let greet = "hello world!"
    print(greet[greet.index(after: greet.startIndex)]) // "e"
    
    #6 使用 index(_ i: String.Index, offsetBy n: int) -> String.Index
    let greet = "hello world!"
    print(greet[greet.index(greet.startIndex, offsetBy: 4)]) // "o"
    
    #7 使用 indices 创建 Range
    let greet = "hello world!"
    for index in greet.indices {
        print("\(greet[index])", terminator: "|")
    }
    // h|e|l|l|o| |w|o|r|l|d|!|Index(_compoundOffset: 0, _cache: Swift.String.Index._Cache.utf16)
    

    字符串增删改查

    主要用到这几个方法:

    • insert(newElement: Character, at: String.Index): 可以在一个字符串的指定索引插入一个字符

    • insert(contentsOf: Collection, at: String.Index): 可以在一个字符串的指定索引插入一个字符段

    • remove(at:): 可以在一个字符串指定索引删除一个

    • removeSubrange(_ bounds: Range<String.Index>): 在一个字符串的指定索引删除一个子字符串

      这些方法都遵循 RangeReplaceableCollection 协议,还可以在集合中(比如 Array, Dictionary, Set )使用这些方法

    示例:

    var greet = "hello"
    
    // 在尾部添加单个字符 '!'
    greet.insert("!", at: greet.endIndex) // "hello!"
    
    // 在 '!' 前添加 "world" 字符段
    greet.insert(contentOf: "world", at: greet.index(greet.endIndex, offsetBy: -1)) // "hello world!"
    
    // 在尾部移除单个字符 '!'
    // 返回被移除的字符 "!"
    // 同时greet 变为 "hello world"
    greet.remove(at: greet.index(before: greet.endIndex))
    
    // 移除 " world"
    // 注意 removeSubrange 接受的参数类型是 Range<String> 类型
    // 需要使用到前面学习的区间的表示法
    let range = greet.index(greet.index(greet.endIndex, offsetBy: -6))..<greet.endIndex
    greet.removeSubrange(range) // "hello"
    

    SubString 类型

    当从字符串中获取一个子字符串,得到的是一个 SubString 实例,而不是 String 类型,Swift中如果需要短时间内操作字符串,才会使用SubString,如果要长时间保存结果,就把 SubString 转化为 String 的实例:

    • 两者都在内存里保存字符集
    • 两者不同之处在于性能优化,SubString 可以复用原 String的内存空间,或者另一个SubString 的内存空间
    • String也有同样的优化,但是如果2个String共享内存的话,它们就会相等

    下面示例使用方法:

    • index(of: Character) -> String.Index: 用来查找某个字符的索引
    var greet = "hello, world!"
    let index = greet.index(of: ",") ?? greet.endIndex
    let beginning = greet[..<index] // beginning 的值为 "hello"
    print(type(of: beginning)) // 打印其类型为 "SubString"
    
    // 将其转化为 String 类型, 以便长期存储
    let newString = String(beginning)
    

    本章中其它的字符串方法

    • hasPrefix(_ prefix: String): 字符串是否有某个前缀
    • hasSuffix(_ suffix: String): 字符串是否有某个后缀
    let greet = "hello, world";
    print(greet.hasPrefix("hell")) // true
    print(greet.hasSuffix("world")) // true
    

    另外swift中好像没有类似JS中的 substring 方法对字符进行截取,原生的小伙伴告诉我可以自定义:

    extension String {
      func substring(start: Int, end: Int = 0) -> String? {
        if start > end && end != 0 {
          return nil
        }
        
        let startIndex = self.index(self.startIndex, offsetBy: start)
        let endIndex = end == 0 ? self.endIndex : self.index(self.startIndex, offsetBy: end)
        
        return String(self[startIndex..<endIndex])
      }
    }
    
    // 使用
    let greet = "hello, world!"
    greet.sub(start: 3, end: 7) // "lo,"
    greet.sub(start: 3) // "lo, world!"
    

    总结

    这一章主要讲了swift中的2种(加上SubString应该是3种)类型,以及字符串索引的操作,最复杂的Unicode的相关表示法此处忽略了,待后面再学习。另外介绍了一些操作字符串的方法,还有大把的方法暂时还未接触,待学习。

    相关文章

      网友评论

          本文标题:#3 字符串和字符(Strings and Characters

          本文链接:https://www.haomeiwen.com/subject/gqqjiftx.html