字符和字符串

此文学习Demo练习参考https://developer.apple.com/documentation/swift/string

	/**
     注意
     Swift 的 String 类型与 Foundation NSString 类进行了无缝桥接。Foundation 还对 String 进行扩展使其可以访问 NSString 类型中定义的方法。这意味着调用那些 NSString 的方法,你无需进行任何类型转换。
     */
    //字符串字面量  字符串字面量可以用于为常量和变量提供初始值:
    let someString = "Some String"  //注意,Swift 之所以推断 someString 常量为字符串类型,是因为它使用了字面量方式进行初始化
    
    /**
     多行字符串字面量
     如果你需要一个字符串是跨越多行的,那就使用多行字符串字面量 — 由一对三个双引号包裹着的具有固定顺序的文本字符集:
     一个多行字符串字面量包含了所有的在开启和关闭引号(""")中的行。这个字符从开启引号(""")之后的第一行开始,到关闭引号(""")之前为止。这就意味着字符串开启引号之后(""")或者结束引号(""")之前都没有换行符号。(译者:下面两个字符串其实是一样的,虽然第二个使用了多行字符串的形式)
     */
    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."
                            """
    
    /**字符串字面量的特殊字符
     字符串字面量可以包含以下特殊字符:
     转义字符 \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"# 会打印换行符转义序列(\n)而不是给文字换行。
     如果需要字符串文字中字符的特殊效果,请匹配转义字符(\)后面添加与起始位置个数相匹配的 # 符。 例如,如果您的字符串是 #"Line 1 \nLine 2"# 并且您想要换行,则可以使用 #“Line 1 \#nLine 2”# 来代替。 同样,###"Line1 \###nLine2"### 也可以实现换行效果。
     扩展分隔符创建的字符串文字也可以是多行字符串文字。 您可以使用扩展分隔符在多行字符串中包含文本 """,覆盖原有的结束文字的默认行为。例如:*/
    let threeMoreDoubleQuotationMarks = #"""
                                        Here are three more double quotes: """
                                        """#
    print(threeMoreDoubleQuotationMarks)
    
    //初始化空字符串
    var emptyString = ""               // 空字符串字面量
    var anotherEmptyString = String()  // 初始化方法
    // 两个字符串均为空并等价。
    //可以通过检查 Bool 类型的 isEmpty 属性来判断该字符串是否为空:
    if emptyString.isEmpty {
        print("Nothing to see here")
    }
    // 打印输出:“Nothing to see here”
    
    /**字符串可变性
    你可以通过将一个特定字符串分配给一个变量来对其进行修改,或者分配给一个常量来保证其不会被修改:
     注意
     在 Objective-C 和 Cocoa 中,需要通过选择两个不同的类(NSString 和 NSMutableString)来指定字符串是否可以被修改。
    */
    var variableString = "Horse"
    variableString += " and carriage"
    // variableString 现在为 "Horse and carriage"
    
    let constantString = "Highlander"
    //constantString += " and another Highlander"
    // 这会报告一个编译错误(compile-time error) - 常量字符串不可以被修改。
    
    /**字符串是值类型
     在 Swift 中 String 类型是值类型。如果你创建了一个新的字符串,那么当其进行常量、变量赋值操作,或在函数/方法中传递时,会进行值拷贝。在前述任一情况下,都会对已有字符串值创建新副本,并对该新副本而非原始字符串进行传递或赋值操作。值类型在 结构体和枚举是值类型 中进行了详细描述。
     Swift 默认拷贝字符串的行为保证了在函数/方法向你传递的字符串所属权属于你,无论该值来自于哪里。你可以确信传递的字符串不会被修改,除非你自己去修改它。
     在实际编译时,Swift 编译器会优化字符串的使用,使实际的复制只发生在绝对必要的情况下,这意味着你将字符串作为值类型的同时可以获得极高的性能。
     使用字符
     你可通过 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"
    //你可以用 append() 方法将一个字符附加到一个字符串变量的尾部:
    welcome.append(exclamationMark)
    // welcome 现在等于 "hello there!"
    /**注意
    你不能将一个字符串或者字符添加到一个已经存在的字符变量上,因为字符变量只能包含一个字符。
    如果你需要使用多行字符串字面量来拼接字符串,并且你需要字符串每一行都以换行符结尾,包括最后一行:*/
    let badStart = """
                    one
                    two
                   """
    let end = """
              three
              """
    print(badStart + end)
    // 打印两行:
    // one
    // twothree
    
    let goodStart = """
                    one
                    two

                    """
    print(goodStart + end)
    // 打印三行:
    // one
    // two
    // three
    /**上面的代码,把 badStart 和 end 拼接起来的字符串非我们想要的结果。因为 badStart 最后一行没有换行符,它与 end 的第一行结合到了一起。相反的,goodStart 的每一行都以换行符结尾,所以它与 end 拼接的字符串总共有三行,正如我们期望的那样。*/

    /**字符串插值
     字符串插值是一种构建新字符串的方式,可以在其中包含常量、变量、字面量和表达式。字符串字面量和多行字符串字面量都可以使用字符串插值。你插入的字符串字面量的每一项都在以反斜线为前缀的圆括号中:
     注意
     插值字符串中写在括号中的表达式不能包含非转义反斜杠(\),并且不能包含回车或换行符。不过,插值字符串可以包含其他字面量。*/
    let multiplier = 3
    let message = "\(multiplier) times 2.5 is \(Double(multiplier) * 2.5)"
    // message 是 "3 times 2.5 is 7.5"
    
    /**Unicode
     Unicode是一个用于在不同书写系统中对文本进行编码、表示和处理的国际标准。它使你可以用标准格式表示来自任意语言几乎所有的字符,并能够对文本文件或网页这样的外部资源中的字符进行读写操作。Swift 的 String 和 Character 类型是完全兼容 Unicode 标准的。
     Unicode 标量
     Swift 的 String 类型是基于 Unicode 标量 建立的。Unicode 标量是对应字符或者修饰符的唯一的 21 位数字,例如 U+0061 表示小写的拉丁字母(LATIN SMALL LETTER A)("a"),U+1F425 表示小鸡表情(FRONT-FACING BABY CHICK)("🐥")。
     请注意,并非所有 21 位 Unicode 标量值都分配给字符,某些标量被保留用于将来分配或用于 UTF-16 编码。已分配的标量值通常也有一个名称,例如上面示例中的 LATIN SMALL LETTER A 和 FRONT-FACING BABY CHICK。
     可扩展的字形群集
     每一个 Swift 的 Character 类型代表一个可扩展的字形群。而一个可扩展的字形群构成了人类可读的单个字符,它由一个或多个(当组合时) Unicode 标量的序列组成。
     举个例子,字母 é 可以用单一的 Unicode 标量 é(LATIN SMALL LETTER E WITH ACUTE, 或者 U+00E9)来表示。然而一个标准的字母 e(LATIN SMALL LETTER E 或者 U+0065) 加上一个急促重音(COMBINING ACTUE ACCENT)的标量(U+0301),这样一对标量就表示了同样的字母 é。 这个急促重音的标量形象的将 e 转换成了 é。
     在这两种情况中,字母 é 代表了一个单一的 Swift 的 Character 值,同时代表了一个可扩展的字形群。在第一种情况,这个字形群包含一个单一标量;而在第二种情况,它是包含两个标量的字形群:*/
    
    let eAcute: Character = "\u{E9}"                         // é
    let combinedEAcute: Character = "\u{65}\u{301}"          // e 后面加上
    // eAcute 是 é, combinedEAcute 是 é
    //可扩展的字形集是一个将许多复杂的脚本字符表示为单个字符值的灵活方式。例如,来自朝鲜语字母表的韩语音节能表示为组合或分解的有序排列。在 Swift 都会表示为同一个单一的 Character 值:
    let precomposed: Character = "\u{D55C}"                  // 한
    let decomposed: Character = "\u{1112}\u{1161}\u{11AB}"   // ᄒ, ᅡ, ᆫ
    // precomposed 是 한, decomposed 是 한
    //可拓展的字符群集可以使包围记号(例如 COMBINING ENCLOSING CIRCLE 或者 U+20DD)的标量包围其他 Unicode 标量,作为一个单一的 Character 值:
    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”
    
    //注意在 Swift 中,使用可拓展的字符群集作为 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 标量组成。这意味着不同的字符以及相同字符的不同表示方式可能需要不同数量的内存空间来存储。所以 Swift 中的字符在一个字符串中并不一定占用相同的内存空间数量。因此在没有获取字符串的可扩展的字符群的范围时候,就不能计算出字符串的字符数量。如果你正在处理一个长字符串,需要注意 count 属性必须遍历全部的 Unicode 标量,来确定字符串的字符数量。
     另外需要注意的是通过 count 属性返回的字符数量并不总是与包含相同字符的 NSString 的 length 属性相同。NSString 的 length 属性是利用 UTF-16 表示的十六位代码单元数字,而不是 Unicode 可扩展的字符群集。*/
    
    /**访问和修改字符串
     你可以通过字符串的属性和方法来访问和修改它,当然也可以用下标语法完成。
     字符串索引
     每一个 String 值都有一个关联的索引(index)类型,String.Index,它对应着字符串中的每一个 Character 的位置。
     前面提到,不同的字符可能会占用不同数量的内存空间,所以要知道 Character 的确定位置,就必须从 String 开头遍历每一个 Unicode 标量直到结尾。因此,Swift 的字符串不能用整数(integer)做索引。
     使用 startIndex 属性可以获取一个 String 的第一个 Character 的索引。使用 endIndex 属性可以获取最后一个 Character 的后一个位置的索引。因此,endIndex 属性不能作为一个字符串的有效下标。如果 String 是空串,startIndex 和 endIndex 是相等的。
     通过调用 String 的 index(before:) 或 index(after:) 方法,可以立即得到前面或后面的一个索引。你还可以通过调用 index(_:offsetBy:) 方法来获取对应偏移量的索引,这种方式可以避免多次调用 index(before:) 或 index(after:) 方法。
     你可以使用下标语法来访问 String 特定索引的 Character。*/
    
    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: endIndex)  error
    //使用 indices 属性会创建一个包含全部索引的范围(Range),用来在一个字符串中访问单个字符。
    for index in greeting.indices {
        print("\(greeting[index]) ", terminator: "")
    }
    // 打印输出“G u t e n   T a g ! ”
    /**注意
    你可以使用 startIndex 和 endIndex 属性或者 index(before:) 、index(after:) 和 index(_:offsetBy:) 方法在任意一个确认的并遵循 Collection 协议的类型里面,如上文所示是使用在 String 中,你也可以使用在 Array、Dictionary 和 Set 中。*/
    
    /**插入和删除
    调用 insert(_:at:) 方法可以在一个字符串的指定索引插入一个字符,调用 insert(contentsOf:at:) 方法可以在一个字符串的指定索引插入一个段字符串。*/
    var welcome2 = "hello"
    welcome2.insert("!", at: welcome2.endIndex)
    // welcome2 变量现在等于 "hello!"
    
    welcome2.insert(contentsOf:" there", at: welcome2.index(before: welcome2.endIndex))
    // welcome2 变量现在等于 "hello there!"
    //调用 remove(at:) 方法可以在一个字符串的指定索引删除一个字符,调用 removeSubrange(_:) 方法可以在一个字符串的指定索引删除一个子字符串。
    welcome2.remove(at: welcome2.index(before: welcome2.endIndex))
    // welcome 现在等于 "hello there"
    
    let range = welcome2.index(welcome2.endIndex, offsetBy: -6)..<welcome2.endIndex
    welcome2.removeSubrange(range)
    // welcome2 现在等于 "hello"
    /**注意
    你可以使用 insert(_:at:)、insert(contentsOf:at:)、remove(at:) 和 removeSubrange(_:) 方法在任意一个确认的并遵循 RangeReplaceableCollection 协议的类型里面,如上文所示是使用在 String 中,你也可以使用在 Array、Dictionary 和 Set 中。*/

    /**子字符串
     当你从字符串中获取一个子字符串 —— 例如,使用下标或者 prefix(_:) 之类的方法 —— 就可以得到一个 SubString 的实例,而非另外一个 String。Swift 里的 SubString 绝大部分函数都跟 String 一样,意味着你可以使用同样的方式去操作 SubString 和 String。然而,跟 String 不同的是,你只有在短时间内需要操作字符串时,才会使用 SubString。当你需要长时间保存结果时,就把 SubString 转化为 String 的实例:
     就像 String,每一个 SubString 都会在内存里保存字符集。而 String 和 SubString 的区别在于性能优化上,SubString 可以重用原 String 的内存空间,或者另一个 SubString 的内存空间(String 也有同样的优化,但如果两个 String 共享内存的话,它们就会相等)。这一优化意味着你在修改 String 和 SubString 之前都不需要消耗性能去复制内存。就像前面说的那样,SubString 不适合长期存储 —— 因为它重用了原 String 的内存空间,原 String 的内存空间必须保留直到它的 SubString 不再被使用为止。
     上面的例子,greeting 是一个 String,意味着它在内存里有一片空间保存字符集。而由于 beginning 是 greeting 的 SubString,它重用了 greeting 的内存空间。相反,newString 是一个 String —— 它是使用 SubString 创建的,拥有一片自己的内存空间。
     注意
     String 和 SubString 都遵循 StringProtocol<//apple_ref/swift/intf/s:s14StringProtocolP> 协议,这意味着操作字符串的函数使用 StringProtocol 会更加方便。你可以传入 String 或 SubString 去调用函数。
     */
    let greetinge = "Hello, world!"
    let indext = greetinge.firstIndex(of: ",") ?? greetinge.endIndex
    let beginninge = greetinge[..<indext]
    // beginning 的值为 "Hello"
    
    // 把结果转化为 String 以便长期存储。
    let newString = String(beginninge)
    
    /**比较字符串
     Swift 提供了三种方式来比较文本值:字符串字符相等、前缀相等和后缀相等。
     字符串/字符相等
     字符串/字符可以用等于操作符(==)和不等于操作符(!=),详细描述在 比较运算符:*/
    let quotation2 = "We're a lot alike, you and I."
    let sameQuotation = "We're a lot alike, you and I."
    if quotation2 == sameQuotation {
        print("These two strings are considered equal")
    }
    // 打印输出“These two strings are considered equal”
    /**前缀/后缀相等
     通过调用字符串的 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”
    /**注意
     hasPrefix(_:) 和 hasSuffix(_:) 方法都是在每个字符串中逐字符比较其可扩展的字符群集是否标准相等,详细描述在 字符串/字符相等。*/
    /**字符串的 Unicode 表示形式
     当一个 Unicode 字符串被写进文本文件或者其他储存时,字符串中的 Unicode 标量会用 Unicode 定义的几种 编码格式(encoding forms)编码。每一个字符串中的小块编码都被称 代码单元(code units)。这些包括 UTF-8 编码格式(编码字符串为 8 位的代码单元), UTF-16 编码格式(编码字符串位 16 位的代码单元),以及 UTF-32 编码格式(编码字符串32位的代码单元)。
     Swift 提供了几种不同的方式来访问字符串的 Unicode 表示形式。你可以利用 for-in 来对字符串进行遍历,从而以 Unicode 可扩展的字符群集的方式访问每一个 Character 值。该过程在 使用字符 中进行了描述。
     另外,能够以其他三种 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 表示
     你可以通过遍历 String 的 utf8 属性来访问它的 UTF-8 表示。其为 String.UTF8View 类型的属性,UTF8View 是无符号 8 位(UInt8)值的集合,每一个 UInt8 值都是一个字符的 UTF-8 表示:
                D          o          g           ‼          🐶
     Character
                U+0044     U+006F     U+0067      U+203C     U+1F436
     
     UTF-8
                68         111        103         226        128    188 240 159 144 182
     Code Unit
     
     Position   0           1          2           3          4       5   6  7   8   9
     上面的例子中,前三个 10 进制 codeUnit 值(68、111、103)代表了字符 D、o 和 g,它们的 UTF-8 表示与 ASCII 表示相同。接下来的三个 10 进制 codeUnit 值(226、128、188)是 DOUBLE EXCLAMATION MARK 的3字节 UTF-8 表示。最后的四个 codeUnit 值(240、159、144、182)是 DOG FACE 的4字节 UTF-8 表示
     
     UTF-16
                68         111        103         8252       55357      56374
     Code Unit
     
     Position   0            1          2           3           4          5
     同样,前三个 codeUnit 值(68、111、103)代表了字符 D、o 和 g,它们的 UTF-16 代码单元和 UTF-8 完全相同(因为这些 Unicode 标量表示 ASCII 字符)。
     第四个 codeUnit 值(8252)是一个等于十六进制 203C 的的十进制值。这个代表了 DOUBLE EXCLAMATION MARK 字符的 Unicode 标量值 U+203C。这个字符在 UTF-16 中可以用一个代码单元表示。
     第五和第六个 codeUnit 值(55357 和 56374)是 DOG FACE 字符的 UTF-16 表示。第一个值为 U+D83D(十进制值为 55357),第二个值为 U+DC36(十进制值为 56374)。
     */
     
    for codeUnit in dogString.utf16 {
        print("\(codeUnit) ", terminator: "")
    }
    print("")
    // 68 111 103 8252 55357 56374
    
    /**
    Unicode 标量表示
    你可以通过遍历 String 值的 unicodeScalars 属性来访问它的 Unicode 标量表示。其为 UnicodeScalarView 类型的属性,UnicodeScalarView 是 UnicodeScalar 类型的值的集合。
    每一个 UnicodeScalar 拥有一个 value 属性,可以返回对应的 21 位数值,用 UInt32 来表示:
     
                D          o          g           ‼          🐶
     Character
                U+0044     U+006F     U+0067      U+203C     U+1F436
     
     Unicode Scalar
                68         111        103         8252        128054
     Code Unit
     
     Position   0           1          2            3            4
    
    */
    for scalar in dogString.unicodeScalars {
        print("\(scalar.value) ", terminator: "")
    }
    print("")
    // 68 111 103 8252 128054
    /**前三个 UnicodeScalar 值(68、111、103)的 value 属性仍然代表字符 D、o 和 g。
    第四个 codeUnit 值(8252)仍然是一个等于十六进制 203C 的十进制值。这个代表了 DOUBLE EXCLAMATION MARK 字符的 Unicode 标量 U+203C。
    第五个 UnicodeScalar 值的 value 属性,128054,是一个十六进制 1F436 的十进制表示。其等同于 DOG FACE 的 Unicode 标量 U+1F436。
    作为查询它们的 value 属性的一种替代方法,每个 UnicodeScalar 值也可以用来构建一个新的 String 值,比如在字符串插值中使用:
     */
    for scalar in dogString.unicodeScalars {
        print("\(scalar) ")
    }
    // D
    // o
    // g
    // ‼
    // 🐶



	//1.判断是否为空:isEmpty
    var str: String = ""
    if str.isEmpty {
        print("isEmpty")
    }
    
    //2.获取字符数量:string.count
    str = "百度baid.com"
    print("\(str.count)个字符")
    
    //3.检查字符串是否有特定前缀/后缀:hasPrefix/hasSuffix
    if str.hasPrefix("http") {
        print("前缀")
    }
    if str.hasSuffix(".com") {
        print("后缀")
    }
    
    //4.还可以用“\()”在字符串里包裹变量,常量
    let name = "欢迎来到\(str)"
    print(name)
    
    //5.多行字符串字面量(多行文字)Swift 4后 可以把字符串写在一对 """ 中,这样字符串就可以写成多行。
    
    str = """
    没有坚毅的毅力
    就没有更多的收获
    """
    print(str)

    //6.大小写转换通过字符串的 uppercased()、lowercase() 方法、capitalized 属性来访问一个字符串的大写/小写/首字母大写
    str = "Welcome to cocoachina"
    let uppercased = str.uppercased()
    let lowercse = str.lowercased()
    let capitalized = str.capitalized
    print(uppercased, lowercse, capitalized)
    
    //字符串截取
    //(1)将String转换为NSString在截取
    let formStr = (str as NSString).substring(from: 11)
    print(formStr)
    let toStr = (str as NSString).substring(to: 7)
    print(toStr)
    let rangStr = (str as NSString).substring(with: NSMakeRange(8, 2))
    print(rangStr)
    
    //(2)直接调用String的对应方法(不推荐:subString现已废弃)
    let index = str.index(str.startIndex, offsetBy: 11)
    let indexFormStr = str.substring(from: index)
    print(indexFormStr)
    let index2 = str.index(str.endIndex, offsetBy: -5)
    let indexToStr = str.substring(to: index2)
    print(indexToStr)
    let range = Range(uncheckedBounds: (lower: index, upper: index2))
    let rangeStr = str.substring(with: range)
    print(rangeStr)
    //(3)推荐使用如下方式
    let indexStr = str[index..<str.endIndex]
    print(indexStr)
    let leftStr = str[..<index]
    print(leftStr)
    let centerStr = str[...index]
    print(centerStr)
    let rightStr = str[index...]
    print(rightStr)
    //(4)还可以通过Prefix和suffix方法进行单边截取
    let prefixStr = str.prefix(11)
    let prefixUpStr = str.prefix(upTo: index)
    let prefixThrouStr = str.prefix(through: index)
    print(prefixStr, prefixUpStr, prefixThrouStr)
    //从后向前截取index位字符
    let subStr = str.suffix(10)
    let suffixStr = str.suffix(from: index)
    print(subStr, suffixStr)
    
    
    //8.获取某个下标索引的前一个、后一个下标对应的字符
    //获取字符串开始索引后一个下标对应的字符
    let startIndex = str.startIndex
    let char1 = str[str.index(after: startIndex)]
    //获取字符串结束索引前一个下标对应的字符
    let endIndex = str.endIndex //endIndex在值上与字符串的长度相等
    let char2 = str[str.index(before: endIndex)]
    print(char1, char2)
    
    //9.获取某个字符串在父串的范围
    let ran = str.range(of: "to")
    print(ran!)
    
    //10.获取某个字符串在父串中开始位置索引(或最后一次出现位置)
    //(2)
    let str1 = "欢迎访问cocoachina。cocoachina做最好的开发者知识平台"
    let str2 = "cocoachina"
    let position1 = str1.positionOf(sub: str2)
    print("子字符串第一次出现的位置是:\(position1)")
    let position2 = str1.positionOf(sub: str2, backwards: true)
    print("子字符串最后一次出现的位置是:\(position2)")
    
    
    //11.追加字符串(拼接字符串)
    str.append("欢迎您")
    print(str)
    
    //12.在指定位置插入字符
    //(1)插入一个字符
    str.insert(" ", at: str.index(str.endIndex, offsetBy: -3))
    print(str)
    //插入一组字符
    str.insert(contentsOf: ["@", "#", "$"], at: str.index(str.endIndex, offsetBy: -3))
    print(str)
    
    //13.在指定范围替换一个字符串
    str.replaceSubrange(str.index(str.endIndex, offsetBy: -3)..<str.endIndex, with: "")
    print(str)
    
    //14.删除指定范围的字符串
    str.removeSubrange(str.index(str.endIndex, offsetBy: -4)..<str.endIndex)
    print(str)
    
    //15.删除第一个字符串
    print(str.dropFirst())
    print(str.dropFirst(3))
    //最后一个
    print(str.dropLast())
    print(str.dropLast(7))

    //16.字符串反转
    print(String(str.reversed()))
    
    //17.遍历字符串里的字符
    for c in str {
        print(c)
    }
    
    str.forEach { (c) in
        print(c)
    }
    
    str.forEach {
        print($0)
    }
    
    //18.获取字符对应的ASCII编码
    let character: Character = "a"
    let unicodeScalars = character.unicodeScalars
    let starIndex = unicodeScalars.startIndex
    let asciiCode = unicodeScalars[starIndex].value
    print(asciiCode)
    
    //19.map方法
    str = "cocoaPods"
    _ = str.map({
        print($0)
    })
    
    //20.filter方法
    let filtered = str.filter { $0 == "d"}
    print(filtered)
    
    //21.reduce方法
    let result = str.reduce("reduce") { (result, c) -> String in
        print(result, c)
        return result + String(c)
    }
    print("最终结果:\(result)")
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值