美文网首页
3、【Swift】字符串

3、【Swift】字符串

作者: Sunday_David | 来源:发表于2020-12-09 08:49 被阅读0次

    字符串和字符

    • 字符串 String是字符Character的集合
    • 通过 + 符号就可拼接两个字符串
    • 能否更改字符串的值,取决于其被定义为常量还是变量

    Swift 的 String 类型与 Foundation NSString 类进行了无缝桥接。调用 NSString 的方法,无需进行类型转换。

    更多关于在 Foundation 和 Cocoa 中使用 String 的信息请查看 Bridging Between String and NSString

    字符串字面量

    • 字符串字面量作为常量或者变量的初始值:
    let someString = "Some string literal value"
    

    多行字符串字面量

    • 用三个双引号引起来的一系列字符
    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 softWrappedQuotation = """
    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."
    """
    
    • 可以在代码中,使用缩进,让代码工整对齐,但字符串里不会有影响
    image
    • 如果你在某行的空格超过了结束的双引号( """ ),那么这些空格被包含。

    字符串字面量的特殊字符

    • 转义特殊字符 \0 (空字符), \ (反斜杠), \t (水平制表符), \n (换行符), \r(回车符), " (双引号) 以及 ' (单引号)

    • Unicode 标量,写成 \u{n}(u 为小写),其中 n 为任意一到八位十六进制数且可用的 Unicode 位码

    let wiseWords = "\"Imagination is more important than knowledge\" - Einstein"
    // "Imageination is more important than knowledge" - Enistein
    let dollarSign = "\u{24}"             // $,Unicode 标量 U+0024
    let blackHeart = "\u{2665}"           // ♥,Unicode 标量 U+2665
    let sparklingHeart = "\u{1F496}"      // 💖,Unicode 标量 U+1F496
    
    • 多行字符串, 直接使用双引号(")而不必加上转义符(\
    • 多行字符串字面量中使用 """, 使用至少一个转义符(\
    let threeDoubleQuotes = """
    Escaping the first quote \"""
    Escaping all three quotes \"\"\"
    """
    

    扩展字符串分隔符

    • 井号( # )包裹,可以使特殊字符不生效
    #"Line 1\nLine 2"#
    
    • 使某个特殊字符生效,使用#号标记
    #"Line 1\#nLine 2"#
    
    ###"Line1\###nLine2"###
    
    • 多行字符串,包含"""
    let threeMoreDoubleQuotationMarks = #"""
    Here are three more double quotes: """
    """#
    

    初始化空字符串

    var emptyString = ""               // 空字符串字面量
    var anotherEmptyString = String()  // 初始化方法
    // 两个字符串均为空并等价。
    
    • 通过检查 Bool 类型的 isEmpty 属性来判断该字符串是否为空
    if emptyString.isEmpty {
        print("Nothing to see here")
    }
    // 打印输出:“Nothing to see here”
    

    字符串可变性

    var variableString = "Horse"
    variableString += " and carriage"
    // variableString 现在为 "Horse and carriage"
    
    let constantString = "Highlander"
    constantString += " and another Highlander"
    // 这会报告一个编译错误(compile-time error) - 常量字符串不可以被修改。
    

    字符串是值类型

    • Swift 中 String 类型是值类型

    • 如果你创建了一个新的字符串,那么当其进行常量、变量赋值操作,或在函数/方法中传递时,会进行值拷贝。

    使用字符

    • for-in 循环来遍历, 获取字符串中每一个字符的值
    for character in "Dog!🐶" {
        print(character)
    }
    // D
    // o
    // g
    // !
    // 🐶
    
    • Character 类型
    let exclamationMark: Character = "!"
    
    • 字符串可通过值类型为 Character 的数组来初始化
    let catCharacters: [Character] = ["C", "a", "t", "!", "🐱"]
    let catString = String(catCharacters)
    print(catString)
    // 打印输出:“Cat!🐱”
    

    连接字符串和字符

    • 通过加法运算符(+)相加在一起(或称“连接”)创建一个新的字符串:
    let string1 = "hello"
    let string2 = " there"
    var welcome = string1 + string2
    // welcome 现在等于 "hello there"
    
    • 通过加法赋值运算符(+=)将一个字符串, 添加到另一个字符串变量上:
    var instruction = "look over"
    instruction += string2
    // instruction 现在等于 "look over there"
    

    你不能把 String或者 Character追加到已经存在的 Character变量当中,因为 Character值能且只能包含一个字符。

    字符串插值

    • 字符串插值:在字符串中插入 常量、变量、字面量、表达式
    let multiplier = 3
    let message = "\(multiplier) times 2.5 is \(Double(multiplier) * 2.5)"
    // message 是 "3 times 2.5 is 7.5"
    
    • 扩展字符串分隔符 使插值符号失效/不生效
    print(#"Write an interpolated string in Swift using \(multiplier)."#)
    // 打印 "Write an interpolated string in Swift using \(multiplier)."
    
    • 部分生效
    print(#"\(6 * 7)  times  is \#(6 * 7)."#)
    // 打印 \(6 * 7)  times  is 42.
    

    Unicode

    • Swift 的 StringCharacter 类型是完全兼容 Unicode 标准的。

    Unicode 标量

    • String 类型是基于 Unicode 标量 建立

    • Unicode 标量: 是对应字符或者修饰符的唯一的 21 位数字

    • U+0061 表示小写的拉丁字母(LATIN SMALL LETTER A)("a")

    • U+1F425 表示小鸡表情(FRONT-FACING BABY CHICK)("🐥")

    print("\u{0061}")// a
    print("--------------------")
    print("\u{1F425}")// 🐥
    print("--------------------")
    

    Unicode 标量码位位于 U+0000到 U+D7FF或者 U+E000到 U+10FFFF之间。Unicode 标量码位不包括从 U+D800到 U+DFFF的16位码元码位。

    • 不是所有的 21 位 Unicode 标量都指定了字符——有些标量是为将来所保留或用于 UTF-16 编码。
    • 有了字符的标量通常来说也会有个名字,比如上边例子中的 LATIN SMALL LETTER AFRONT-FACING BABY CHICK

    可扩展的字形群集

    • Character 类型代表一个可扩展的字形集
    • 一个可扩展的字形群构成了人类可读的单个字符,它由一个或多个 Unicode 标量的序列组成。

    • 字母 é 代表了一个单一的 Swift 的 Character 值, 同时代表了一个可扩展的字形群
    • 第一种情况,这个字形群包含一个单一标量
    • 第二种情况,它是包含两个标量的字形群
    let eAcute: Character = "\u{E9}"                         // é
    let combinedEAcute: Character = "\u{65}\u{301}"          // e 后面加上  ́
    // eAcute 是 é, combinedEAcute 是 é
    

    • 可扩展的字形集: 是一个将许多复杂的脚本字符, 表示为单个字符值的灵活方式

    • 朝鲜语字母表的韩语音节能表示为组合或分解的有序排列

    let precomposed: Character = "\u{D55C}"                  // 한
    let decomposed: Character = "\u{1112}\u{1161}\u{11AB}"   // ᄒ, ᅡ, ᆫ
    // precomposed 是 한, decomposed 是 한
    

    • 扩展字形集群允许封闭标记的标量 (比如 COMBINING ENCLOSING CIRCLE, 或者说 U+20DD) 作为单一 Character值来圈住其他 Unicode 标量:
    let enclosedEAcute: Character = "\u{E9}\u{20DD}"
    // enclosedEAcute 是 é⃝
    

    • 区域指示符号的 Unicode 标量可以成对组合来成为单一的 Character值,比如说这个 REGIONAL INDICATOR SYMBOL LETTER U ( U+1F1FA)和 REGIONAL INDICATOR SYMBOL LETTER S (U+1F1F8):
    let regionalIndicatorForUS: Character = "\u{1F1FA}\u{1F1F8}"
    // regionalIndicatorForUS 是 🇺🇸
    

    计算字符数量/字符统计

    • Character值的总数,使用字符串的 count属性
    let unusualMenagerie = "Koala 🐨, Snail 🐌, Penguin 🐧, Dromedary 🐪"
    print("unusualMenagerie has \(unusualMenagerie.count) characters")
    // 打印输出“unusualMenagerie has 40 characters”
    

    注意: 使用可拓展的字符群集作为 Character 值来连接或改变字符串时,并不一定会更改字符串的字符数量。

    var word = "cafe"
    print("the number of characters in \(word) is \(word.count)")
    // 打印输出“the number of characters in cafe is 4”
    
    word += "\u{301}"    // 拼接一个重音,U+0301
    
    print("the number of characters in \(word) is \(word.count)")
    // 打印输出“the number of characters in café is 4”          
    
    • 扩展字形集群能够组合一个或者多个 Unicode 标量。这意味着不同的字符——以及相同字符的不同表示——能够获得不同大小的内存来储存. 特殊的长字符串值,要注意 count属性为了确定字符串中的字符要遍历整个字符串的 Unicode 标量。
    • count 属性返回的字符数量并不总是与包含相同字符的 NSStringlength 属性相同
    • NSStringlength 属性是利用 UTF-16 表示的十六位代码单元数字,而不是 Unicode 可扩展的字符群集

    访问和修改字符串

    • 通过字符串的属性和方法来访问和修改它,当然也可以用下标语法完成

    字符串索引

    • 每一个 String 值都有一个关联的索引(index)类型,String.Index,它对应着字符串中的每一个 Character 的位置
    • 使用 startIndex属性来访问 String中第一个 Character的位置
    • endIndex属性就是 String中最后一个字符后的位置
    • endIndex属性并不是字符串下标脚本的合法实际参数。如果String为空,则 startIndex与 endIndex相等。
    • 用 index(before:) 和 index(after:) 方法来访问给定索引的前后
    • 给定索引更远的索引,你可以使用 index(_:offsetBy:) 方法
    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
    
    • 获取越界索引对应的 Character,将引发一个运行时错误。
    greeting[greeting.endIndex] // error
    greeting.index(after: greeting.endIndex) // error
    
    • indices 属性会创建一个包含全部索引的范围(Range
    for index in greeting.indices {
       print("\(greeting[index]) ", terminator: "")
    }
    // 打印输出“G u t e n   T a g ! ”
    

    可以在任何遵循了 Collection 协议的类型中使用 startIndex 和 endIndex 属性以及 index(before:) ,index(after:) 和 index(_:offsetBy:) 方法。这包括这里使用的 String ,还有集合类型比如 Array ,Dictionary 和 Set

    插入和删除

    • 特定位置插入字符,使用 insert(_:at:)方法
    • 插入一个段字符串, 调用 insert(contentsOf:at:) 方法
    var welcome = "hello"
    welcome.insert("!", at: welcome.endIndex)
    // welcome 变量现在等于 "hello!"
    
    welcome.insert(contentsOf:" there", at: welcome.index(before: welcome.endIndex))
    // welcome 变量现在等于 "hello there!"
    
    • 移除字符,使用 remove(at:)方法
    • 移除一小段字符串,removeSubrange(_:)
    welcome.remove(at: welcome.index(before: welcome.endIndex))
    // welcome 现在等于 "hello there"
    
    let range = welcome.index(welcome.endIndex, offsetBy: -6)..<welcome.endIndex
    welcome.removeSubrange(range)
    // welcome 现在等于 "hello" 
    

    任意一个确认的并遵循 RangeReplaceableCollection 协议的类型里面,可使用 insert(_:at:)insert(contentsOf:at:)remove(at:)removeSubrange(_:) 方法, 在如上文用在 String 中,也用在 ArrayDictionarySet

    子字符串

    • 使用下标或者 prefix(_:) 之类的方法 —— 就可以得到一个 Substring 的实例,而非另外一个 String
    • Substring 绝大部分函数都跟 String 一样
    • 与字符串不同,在字符串上执行动作的话你应该使用子字符串执行短期处理。当你想要把结果保存得长久一点时,你需要把子字符串转换为 String 实例
    let greeting = "Hello, world!"
    let index = greeting.index(of: ",") ?? greeting.endIndex
    let beginning = greeting[..<index]
    // beginning is "Hello"
     
    // Convert the result to a String for long-term storage.
    let newString = String(beginning)
    
    • Substring 可以重用原 String 的内存空间,或者另一个 Substring 的内存空间
    • newString 是一个 String —— 它是使用 Substring 创建的,拥有一片自己的内存空间。
    img

    StringSubstring 都遵循 StringProtocol 协议,这意味着操作字符串的函数使用 StringProtocol 会更加方便。你可以传入 StringSubstring 去调用函数

    比较字符串

    三种方式比较文本值:字符串字符相等、前缀相等和后缀相等。

    字符串/字符相等

    let quotation = "We're a lot alike, you and I."
    let sameQuotation = "We're a lot alike, you and I."
    if quotation == sameQuotation {
        print("These two strings are considered equal")
    }
    // 打印输出“These two strings are considered equal”
    
    • 两个字符串(或者两个字符)的可扩展的字形群集是标准相等,那它们是相等的,
    • 只要可扩展的字形群集有同样的语言意义和外观, 即使它们是由不同的 Unicode 标量构成

    • 如,LATIN SMALL LETTER E WITH ACUTE(U+00E9)就是标准相等于 LATIN SMALL LETTER E(U+0065)后面加上 COMBINING ACUTE ACCENT(U+0301)
    // "Voulez-vous un café?" 使用 LATIN SMALL LETTER E WITH ACUTE
    let eAcuteQuestion = "Voulez-vous un caf\u{E9}?"
    
    // "Voulez-vous un café?" 使用 LATIN SMALL LETTER E and COMBINING ACUTE ACCENT
    let combinedEAcuteQuestion = "Voulez-vous un caf\u{65}\u{301}?"
    
    if eAcuteQuestion == combinedEAcuteQuestion {
        print("These two strings are considered equal")
    }
    // 打印输出“These two strings are considered equal”
    
    • 相反,英语中的 LATIN CAPITAL LETTER A(U+0041,或者 A)不等于俄语中的 CYRILLIC CAPITAL LETTER A(U+0410,或者 A)。两个字符看着是一样的,但却有不同的语言意义:
    let latinCapitalLetterA: Character = "\u{41}"
    
    let cyrillicCapitalLetterA: Character = "\u{0410}"
    
    if latinCapitalLetterA != cyrillicCapitalLetterA {
        print("These two characters are not equivalent")
    }
    // 打印“These two characters are not equivalent”
    

    前缀/后缀相等

    • hasPrefix(_:)/hasSuffix(_:) 方法检查字符串是否有特定前缀/后缀,两个方法均接收一个 String 类型的参数,并返回一个布尔值
    let romeoAndJuliet = [
        "Act 1 Scene 1: Verona, A public place",
        "Act 1 Scene 2: Capulet's mansion",
        "Act 1 Scene 3: A room in Capulet's mansion",
        "Act 1 Scene 4: A street outside Capulet's mansion",
        "Act 1 Scene 5: The Great Hall in Capulet's mansion",
        "Act 2 Scene 1: Outside Capulet's mansion",
        "Act 2 Scene 2: Capulet's orchard",
        "Act 2 Scene 3: Outside Friar Lawrence's cell",
        "Act 2 Scene 4: A street in Verona",
        "Act 2 Scene 5: Capulet's mansion",
        "Act 2 Scene 6: Friar Lawrence's cell"
    ]
    
    • hasPrefix(_:) 方法来计算话剧中第一幕的场景数:
    var act1SceneCount = 0
    for scene in romeoAndJuliet {
        if scene.hasPrefix("Act 1 ") {
            act1SceneCount += 1
        }
    }
    print("There are \(act1SceneCount) scenes in Act 1")
    // 打印输出“There are 5 scenes in Act 1”
    
    • hasSuffix(_:) 方法来计算发生在不同地方的场景数:
    var mansionCount = 0
    var cellCount = 0
    for scene in romeoAndJuliet {
        if scene.hasSuffix("Capulet's mansion") {
            mansionCount += 1
        } else if scene.hasSuffix("Friar Lawrence's cell") {
            cellCount += 1
        }
    }
    print("\(mansionCount) mansion scenes; \(cellCount) cell scenes")
    // 打印输出“6 mansion scenes; 2 cell scenes”
    

    字符串的 Unicode 表示形式

    • 一个 Unicode 字符串被写进文本文件或者其他储存时,字符串中的 Unicode 标量会用 Unicode 定义的几种 编码格式(encoding forms)编码

    • 每一个字符串中的小块编码都被称 代码单元(code units), 包括 UTF-8 编码格式(编码字符串为 8 位的代码单元), UTF-16 编码格式(编码字符串位 16 位的代码单元),以及 UTF-32 编码格式(编码字符串32位的代码单元)

    • 访问字符串的 Unicode 表示形式, 利用 for-in 来对字符串进行遍历

    • 其他三种 Unicode 兼容的方式访问字符串的值

      • UTF-8 代码单元集合(利用字符串的 utf8 属性进行访问)
      • UTF-16 代码单元集合(利用字符串的 utf16 属性进行访问)
      • 21 位的 Unicode 标量值集合,也就是字符串的 UTF-32 编码格式(利用字符串的 unicodeScalars 属性进行访问)
    • D,o,g,(DOUBLE EXCLAMATION MARK, Unicode 标量 U+203C)和 🐶(DOG FACE,Unicode 标量为 U+1F436)组成的字符串中的每一个字符代表着一种不同的表示

    let dogString = "Dog‼🐶"
    

    UTF-8 表示

    • Stringutf8 属性可访问它的 UTF-8 表示
    • String.UTF8View 类型的属性,UTF8View 是无符号 8 位(UInt8)值的集合,每一个 UInt8 值都是一个字符的 UTF-8 表示

    UTF-16 表示

    • Stringutf16 属性来访问它的 UTF-16 表示

    Unicode 标量表示

    • 你可以通过遍历 String 值的 unicodeScalars 属性来访问它的 Unicode 标量表示

    相关文章

      网友评论

          本文标题:3、【Swift】字符串

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