Swift 5.1 (3) - 字符串

字符串
字符串是一系列字符組成的。Swift字符串由String類(lèi)型表示。
1.使用字符串文字作為常量或變量的初始值:

let str = "I am zhangfei"http://str 系統(tǒng)使用類(lèi)型推斷為String類(lèi)型

2.多行字符串:由三個(gè)雙引號(hào)"""括起來(lái)的字符序列。注意:多行字符串文字的正文開(kāi)始以及結(jié)束時(shí),分隔符"""必須獨(dú)占一行。

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 multilineString = """
These are the same.
"""

多行字符串文字中包含換行符時(shí),該換行符也會(huì)出現(xiàn)在字符串的值中。
如果只想使用換行符來(lái)簡(jiǎn)化代碼的讀取,而不希望換行符成為字符串值的一部分,請(qǐng)?jiān)谶@些行的末尾寫(xiě)一個(gè)反斜杠\

/*
 不加反斜杠\打印:
 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."
 加反斜杠\打印:
 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 ontill 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."
"""
print(softWrappedQuotation)

字符串中的特殊字符
字符串中可以包含以下特殊字符:

  • 轉(zhuǎn)義的特殊字符 \ 0(空字符),\\(反斜杠),\ t(水平制表符),\ n(換行符),\ r \ n(回車(chē)符),\"(雙引號(hào))和\'(單
    引號(hào))。
  • 一個(gè)任意的Unicode標(biāo)量值,寫(xiě)為\ u {n},其中n是1-8位十六進(jìn)制數(shù)。

特殊字符示例:

let name = "i am \"張飛\""
let dollarSign = "\u{24}"        // $,  Unicode標(biāo)量 U+0024
let blackHeart = "\u{2665}"      // ,  Unicode標(biāo)量 U+2665
let sparklingHeart = "\u{1F496}" // , Unicode標(biāo)量 U+1F496
print(name+dollarSign+blackHeart+sparklingHeart)//!<i am "張飛"$

因?yàn)槎嘈凶址淖质褂萌齻€(gè)雙引號(hào)"""而不是一個(gè)",故多行字符串文字中包含雙引號(hào)"可以不用轉(zhuǎn)義它。但是要在多行字符串中包含""" ,需要至少轉(zhuǎn)義一個(gè)引號(hào)。

let threeDoubleQuotationMarks = """
Escaping the first quotation mark \"""
Escaping all three quotation marks \"\"\"
"""

擴(kuò)展字符串分隔符: 我們可以將包含特殊字符的字符串放在擴(kuò)展分隔符中,讓所包含的特殊字符(如:轉(zhuǎn)義符)不生效。使用時(shí)將字符串放在引號(hào)"中并用數(shù)字符號(hào)括起來(lái)。#的個(gè)數(shù)不限制,但是數(shù)量需要保持一致性。形式:let str = #"Line 1\nLine 2"#str輸出換行符\n而不是輸出兩行的字符串。
如果需要字符串中特殊字符的特殊效果,則需要在轉(zhuǎn)義字符\后面使用數(shù)字符號(hào)#,但要注意匹配#的個(gè)數(shù)。例如,字符串:let str = #"Line 1\nLine 2"#,我們需要讓換行符\n生效,則可以使用let str = #"Line 1\#nLine 2"#來(lái)代替。同樣,let str = ##"Line 1\##nLine 2"##let str = ###"Line 1\###nLine 2"###也能讓換行符生效。
多行字符串使用擴(kuò)展分隔符而不需要使用轉(zhuǎn)義符\,例如:

let threeQuotationMarks = #"""
Here are three more double quotes: """
"""#
print(threeQuotationMarks)//!< log:Here are three more double quotes: """

初始化一個(gè)空的字符串: 可以使用將空字符串指定給變量,或使用初始化字符串的語(yǔ)法初始化一個(gè)String實(shí)例:

// 一下兩個(gè)字符串都是空的,并且彼此都是相等的
var emptyString = ""        
var anotherEmptyString = String() 

字符串判空:

if emptyString.isEmpty {
    print("空字符串")
}

可變字符串:將特定字符串賦值給變量或常量,來(lái)表示字符串是否可以被修改。
將特定字符串賦值給變量:在這種情況下可以對(duì)其進(jìn)行修改。

var variableString = "Horse"
variableString += " and carriage"
print(variableString)

將特定字符串賦值給常量:在這種情況下無(wú)法對(duì)其進(jìn)行修改。

let constantString = "Highlander"
constantString += " and another Highlander"http://!< 編譯器報(bào)錯(cuò):constantString是常量不可變

這種方法不像Objective-C和Cocoa中的字符串可變,可以在兩個(gè)類(lèi)NSString和NSMutableString之間進(jìn)行選擇,區(qū)分可變字符串。

字符串是值類(lèi)型: Swift的String類(lèi)型是一種值類(lèi)型。如果我們創(chuàng)建一個(gè)新的字符串a,在將a傳遞給函數(shù)或方法時(shí),或?qū)⑵滟x值給常量或變量時(shí),將復(fù)制字符串a的值。在以上每種情況下,都會(huì)創(chuàng)建現(xiàn)有字符串的新副本,并傳遞或分配新副本,而不是原始字符串。
Swift默認(rèn)復(fù)制字符串的行為,確保了在函數(shù)或方法中傳遞字符串時(shí),該字符串的值不會(huì)被改變,無(wú)論它來(lái)自何處,除非我們自己修改。
同時(shí)Swift的編譯器對(duì)字符串的默認(rèn)復(fù)制行為做了優(yōu)化:只有在絕對(duì)必要的情況下才會(huì)進(jìn)行實(shí)際的復(fù)制,保證了性能。

字符使用:我們可以通過(guò)使用for-in循環(huán)遍歷字符串來(lái)訪問(wèn)字符串中各個(gè)字符。

let str = "Dog!"
for character in str {
    print(character)
}

創(chuàng)建一個(gè)Character類(lèi)型的常量或變量

//創(chuàng)建常量
let character : Character = ""
print(character)
//創(chuàng)建變量
var character : Character = ""
character = ""
print(character)

通過(guò)字符數(shù)組,生成一個(gè)字符串

let catCharacters : [Character] = ["c","a","t","i","s",""]
let catString = String(catCharacters)
print(catString)

連接字符串和字符:
字符串可以使用加法運(yùn)算符+連接到一起以創(chuàng)建新的字符串:

let string1 = "hello"
let string2 = " there"
let welcome = string1 + string2
print(welcome)

使用加號(hào)賦值運(yùn)算符+=

var instruction = "look over"
let string2 = " there"
instruction += string2 //!< log:look over there

使用String類(lèi)型的append()方法將Character類(lèi)型的值添加到String類(lèi)型的變量。

var character : Character = ""
character = ""
var instruction = "look over"
let string2 = " there"
instruction += string2
instruction.append(character) //!< look over there

使用多行字符串文字來(lái)構(gòu)建更多行的字符串,則希望字符串中的每一行都以換行符結(jié)束,包括最后一行。

let badStart = """
one
two
"""
let end = """
three
"""
/*輸出兩行:badStart的最后一行不以換行符結(jié)束,所以該行與end的第一行結(jié)合
one
twothree
*/
print(badStart + end)

let goodStart = """
one
two

"""
/*輸出三行:goodStart最后一行以換行符結(jié)束。
one
two
three
*/
print(goodStart + end)

字符串插值:字符串插值是一種通過(guò)在字符串中混合常量,變量,文字和表達(dá)式并可以構(gòu)造出新字符串的方法。
作用:將常量或變量的名稱(chēng)包含在較長(zhǎng)字符串中作為占位符,并提示Swift將其替換為該常量或變量的當(dāng)前值。使用形式:將名稱(chēng)括在括號(hào)中,并在左括號(hào)前用反斜杠轉(zhuǎn)義它\(變量或常量)。單行和多行字符串都可以使用字符串插值。

let multiplier = 3
let message = "\(multiplier) times 2.5 is \(Double(multiplier) * 2.5)"
print(message)//!< 3 times 2.5 is 7.5

上例中\(multiplier)\(Double(multiplier) * 2.5)屬于字符串插值。

print(#"Write an interpolated string in Swift using \(multiplier)."#)//!<Write an interpolated string in Swift using \(multiplier).

上例中使用擴(kuò)展字符串分隔符來(lái)創(chuàng)建包含特殊字符\的字符串,否則這些字符將被視為字符串插值。
若要在使用擴(kuò)展分隔符的字符串中使用字符串插值,需將\后面的數(shù)字符號(hào)#的個(gè)數(shù)與字符串開(kāi)頭和結(jié)尾處#的個(gè)數(shù)相匹配。

print(#"Write an interpolated string in Swift using \#(multiplier)."#)//!<Write an interpolated string in Swift using 3.

Unicode:又名:統(tǒng)一碼、萬(wàn)國(guó)碼、單一碼。它是跨語(yǔ)言、跨平臺(tái)進(jìn)行文本轉(zhuǎn)換、處理的國(guó)際標(biāo)準(zhǔn)。Swift中的字符串和字符類(lèi)型完全符合Unicode。

  1. Unicode標(biāo)量:Swift的原生String類(lèi)型是根據(jù)Unicode標(biāo)量構(gòu)建的。Unicode標(biāo)量:使用21個(gè)二進(jìn)制位表示的字符或修飾符,(注解:目前Unicode的編碼范圍達(dá)到了21位,Unicode標(biāo)量范圍 0x0000 - 0x10ffff 的范圍,二進(jìn)制位為 1 0000 1111 1111 1111 1111,總共21位)例如:U+0061表示a,U+1F425表示``。需要注意的是,Unicode標(biāo)量值并不需要把所有21個(gè)二進(jìn)制位都分配給字符或修飾符 ,某些多出來(lái)的Unicode標(biāo)量會(huì)保留下來(lái),用于將來(lái)分配或用于UTF-16編碼(注解:UTF-16是Unicode的其中一個(gè)使用方式,即把Unicode字符集的抽象碼位映射為16位的序列,用于數(shù)據(jù)存儲(chǔ)或傳遞)。

  2. 擴(kuò)展字形集群:Swift的Character類(lèi)型的每個(gè)實(shí)例,代表一個(gè)擴(kuò)展的字形集群。擴(kuò)展字形集群是一個(gè)或多個(gè)可組合的Unicode標(biāo)量(組合時(shí),產(chǎn)生單個(gè)人類(lèi)可讀字符)的序列。字母é可以表示為單個(gè)Unicode標(biāo)量\u{00E9}。字母é也可以表示為一對(duì)標(biāo)量 :標(biāo)準(zhǔn)字母e:\u{0065}和尖音符\u{301}組合的形式。(音調(diào)符標(biāo)量以圖形方式應(yīng)用于其前面的標(biāo)量,當(dāng)它由具有Unicode感知的文本渲染系統(tǒng)渲染時(shí)將e轉(zhuǎn)換為é)
    在這兩種情況下,字母é表示為單個(gè)Swift中的Character值,表示可擴(kuò)展的字形簇。在第一種情況下,集群中的單個(gè)標(biāo)量;在第二種情況下,它是兩個(gè)標(biāo)量的集群:

let eAcute: Character = "\u{E9}"                         // é
let combinedEAcute: Character = "\u{65}\u{301}" //é
print(String(eAcute)+String(combinedEAcute))

可擴(kuò)展的字形集群是一種將許多復(fù)雜腳本字符表示為單個(gè)字符值的靈活方式。

let precomposed: Character = "\u{D55C}"                  // ?
let decomposed: Character = "\u{1112}\u{1161}\u{11AB}"   // \u{1112}:?, \u{1161}:?,\u{11AB}: ? ->?
print(String(precomposed)+String(decomposed))

區(qū)域指示符號(hào)的Unicode標(biāo)量可以成對(duì)組合以生成單個(gè)字符值,例如區(qū)域指示符符號(hào)U(U + 1F1FA)和區(qū)域指示符符號(hào)字母S(U + 1F1F8)的組合:

let regionalIndicatorForUS: Character = "\u{1F1FA}\u{1F1F8}"
print(String(regionalIndicatorForUS))//log:

字符計(jì)數(shù):檢索字符串中字符的數(shù)目,可以使用字符串的count屬性:

let title = "Koala , Snail , Penguin , Dromedary "
print("title中有\(zhòng)(title.count)個(gè)字符")//!< 40個(gè)字符

需要注意的是:Swift中對(duì)字符串拼接擴(kuò)展字形集群可能并不會(huì)影響字符串的字符數(shù)目。如:

var x = "thing" //!< x.count = 5
x += "\u{301}" //!< x:thin?
print(x) //!< x.count 依舊是5

擴(kuò)展的字形集群可以由多個(gè)Unicode標(biāo)量組成。這意味著相同字符的不同表示可能需要不同的內(nèi)存量來(lái)存儲(chǔ)。因此,在Swift中,字符串的每個(gè)字符在內(nèi)存中所占的大小可能不相同。需要注意的是如果字符串特別長(zhǎng),使用count屬性獲取字符串中字符數(shù)量時(shí),是會(huì)遍歷整個(gè)字符串中的Unicode標(biāo)量的。count屬性可能與包含相同字符的NSString的length屬性返回的字符數(shù)量不相同。因?yàn)閮烧叩挠?jì)算基準(zhǔn)不一樣。NSString的長(zhǎng)度基于字符串的UTF-16表示中的16位碼元的數(shù)量,而不是基于字符串中Unicode可擴(kuò)展的字形集群的數(shù)量。

//OC中計(jì)算的字符數(shù)。
NSString *str = @"Koala , Snail , Penguin , Dromedary ";
NSLog(@"%ld",str.length);//!< 44個(gè)字符

訪問(wèn)和修改字符串:通過(guò)相應(yīng)方法和屬性或使用下標(biāo)語(yǔ)法來(lái)訪問(wèn)和修改字符串。
字符串索引:每個(gè)String值都有一個(gè)關(guān)聯(lián)的索引類(lèi)型String.Index,它對(duì)應(yīng)于字符串中每個(gè)字符的位置。
如上所述,Swift中不同的字符可能需要不同的內(nèi)存量來(lái)存儲(chǔ),因?yàn)镾wift的字符串中字符數(shù)是基于Unicode標(biāo)量的來(lái)計(jì)算的:a.集群中的單個(gè)標(biāo)量,b.多個(gè)標(biāo)量的可擴(kuò)展集群。因此Swift字符串不能用整數(shù)值索引,為了確定某個(gè)特定的字符位于哪個(gè)位置,我們必須從該字符串的開(kāi)頭或結(jié)尾遍歷每個(gè)Unicode標(biāo)量
使用startIndex屬性可以訪問(wèn)字符串的第一個(gè)字符的位置。endIndex屬性是字符串最后一個(gè)字符之后的位置。因此,endIndex屬性不是字符串下標(biāo)的有效參數(shù)。如果字符串為空,則startIndexendIndex相等。可以使用字符串的索引index(before: )index(after:)方法訪問(wèn)給定索引之前和之后的索引。要訪問(wèn)遠(yuǎn)離給定索引的索引,可以使用索引index(_:, offsetBy: )方法,而不是多次調(diào)用其中一種方法。字符串title根據(jù)字符索引獲取字符:title[String.Index(必須是索引類(lèi)型)]

let title = "Koala , Snail , Penguin , Dromedary "
let subStr = title[title.index(after: title.startIndex)]//!< startIndex之后的位置 輸出o
let subStr1 = title[title.index(before: title.endIndex)]//!< 

let subStr2 = title[title.index(title.endIndex, offsetBy: -1)] //!< log:
let subStr3 = title[title.index(title.startIndex, offsetBy: 6)]//!< log: 

let index = title.index(title.startIndex, offsetBy: 15)
let subStr4 = title[index] //!< log:

嘗試訪問(wèn)字符串范圍之外的索引或字符時(shí)將觸發(fā)運(yùn)行時(shí)錯(cuò)誤。

//! 所得索引超越了字符串的有效范圍,觸發(fā)運(yùn)行時(shí)錯(cuò)誤:Thread 1: Fatal error: String index is out of bounds
let outsideIndex = title.index(after: title.endIndex)
//!索引超越了有效范圍,觸發(fā)運(yùn)行時(shí)錯(cuò)誤:Thread 1: Fatal error: String index is out of bounds
let subStr5 = title[title.endIndex]

使用indices屬性可以獲取字符串中所有字符的索引。

let indices = title.indices;//!DefaultIndices<String>(_elements: "Koala , Snail , Penguin , Dromedary ", _startIndex: Swift.String.Index(_rawBits: 0), _endIndex: Swift.String.Index(_rawBits: 3407872))
var tempStr:String = ""
for index in indices {
    print("\(title[index])","",separator: "_", terminator: "", to: &tempStr)
}
////!< 最終合成的新字符串:K_o_a_l_a_ __,_ _S_n_a_i_l_ __,_ _P_e_n_g_u_i_n_ __,_ _D_r_o_m_e_d_a_r_y_ __
print("最終合成的新字符串:\(tempStr)")

重點(diǎn):我們可以在符合Collection協(xié)議的任何類(lèi)型上使用startIndexendIndex屬性以及索引index(before: )index(after:)index(_:, offsetBy: )方法。這包括字符串以及集合類(lèi)型,如Array,Dictionary和Set。
字符串插入和刪除:
插入:字符串指定索引處插入單個(gè)字符使用insert(_:at:)方法;在指定索引處插入另一個(gè)字符串使用insert(contentsOf:at:)方法。

var inserStr = "hello"
//! 插入單個(gè)字符:unicode標(biāo)量
inserStr.insert("\u{1F1F7}", at: inserStr.startIndex)//!< log:hello
//! 插入單個(gè)字符:普通字符
inserStr.insert("!", at: inserStr.endIndex)//!< log:hello! 插入時(shí)可以使用endIndex
//!< 插入字符串:由字符:unicode標(biāo)量組成的字符串
let scalarStr = "\u{1F1F6}\u{1F496}"http://!< 
inserStr.insert(contentsOf: scalarStr, at: inserStr.startIndex)//!< hello!
//! 插入普通字符串:
let normalStr = "_word"
inserStr.insert(contentsOf: normalStr, at: inserStr.index(before: inserStr.endIndex))//!< hello_word!

刪除:字符串刪除指定索引處的單個(gè)字符使用remove(at:)方法;刪除指定范圍內(nèi)的子字符串使用removeSubrange(_:)方法:

//復(fù)雜組成的字符串
var removeStr = "\u{1F1F6}\u{1E67F}\u{1F496}\u{1F1F7}hello_word!eye\u{301}"http://!< log:hello_word!eyé
//移除unicode標(biāo)量字符:
removeStr.remove(at: removeStr.index(removeStr.startIndex, offsetBy: 2))//!< log:hello_word!eyé
//移除普通字符:y 為啥-2因?yàn)閑ndIndex屬性表示字符串最后一個(gè)字符之后的位置
removeStr.remove(at: removeStr.index(removeStr.endIndex, offsetBy: -2))//!< log:hello_word!eé
//!< 刪除子0-1范圍內(nèi)的字符串:由字符:unicode標(biāo)量組成的子字符串:
//*range
//    let range = removeStr.startIndex..<removeStr.index(removeStr.startIndex, offsetBy: 2)
//或
let range = removeStr.startIndex...removeStr.index(removeStr.startIndex, offsetBy: 1)
removeStr.removeSubrange(range) //!< hello_word!eé

注意:String類(lèi)型實(shí)現(xiàn)了RangeReplaceableCollection協(xié)議,其他實(shí)現(xiàn)了RangeReplaceableCollection協(xié)議的任何類(lèi)型都可以使用insert(_:at:)insert(contentsOf:at:)remove(at:)removeSubrange(_:)方法。如:Array,Dictionary和Set。
子字符串:
從字符串中獲取子字符串時(shí) - 例如,使用索引或類(lèi)似prefix(_:)的方法 ,結(jié)果是Substring的實(shí)例,而不是另一個(gè)字符串。Swift中的子字符串與字符串具有多數(shù)相同的方法,這意味著我們可以像處理字符串一樣使用子字符串。但是與字符串不同,我們?cè)趯?duì)字符串執(zhí)行操作時(shí)只會(huì)使用子字符串很短的時(shí)間。當(dāng)我們需要將子字符串存儲(chǔ)更長(zhǎng)時(shí)間時(shí),則需要將子字符串轉(zhuǎn)換為String實(shí)例。

var myString = "\u{1F1F6}\u{1E67F}\u{1F496}\u{1F1F7}hello_word!eye\u{301}"http://!< log:??hello_word!eyé
//從字符串中取出hello子字符串
//1.獲取hello在字符中的范圍
//Returns the last index where the specified value appears in the collection.
let subStart = myString.lastIndex(of:"" ) ?? myString.startIndex //!< 字符的位置
//Returns the first index where the specified value appears in the collection.
let subEnd = myString.firstIndex(of: "_") ?? myString.endIndex//!< 字符_的位置
//2.獲取子字符串
let subString = myString[subStart..<subEnd]//!<log: hello
print(subString)
//3.若需要長(zhǎng)時(shí)間使用子字符串則需要類(lèi)型轉(zhuǎn)換
let longSubStr = String(subString) //!< or:String.init(subString)

重點(diǎn)知識(shí):
字符串和子字符串之間的區(qū)別:與字符串一樣,每個(gè)子字符串都有一個(gè)內(nèi)存區(qū)域,用于存儲(chǔ)構(gòu)成子字符串的字符。但是作為性能優(yōu)化,子字符串可以重用用于存儲(chǔ)原始字符串的部分內(nèi)存,或者用于存儲(chǔ)另一個(gè)子字符串的內(nèi)存的一部分。字符串具有類(lèi)似的優(yōu)化,但如果兩個(gè)字符串共享內(nèi)存,則它們是相等的此性能優(yōu)化意味著在修改字符串或子字符串之前,不會(huì)增加復(fù)制內(nèi)存的性能成本。如上所述,子字符串不適合長(zhǎng)期存儲(chǔ) 因?yàn)樗鼈冎赜迷甲址拇鎯?chǔ),只要使用任何子字符串,整個(gè)原始字符串就必須保存在內(nèi)存中
示例描述:myString是一個(gè)字符串,這意味著它有一個(gè)內(nèi)存區(qū)域,用于存儲(chǔ)構(gòu)成字符串的字符。因?yàn)閟ubString是myString的子字符串,所以它重用了myString使用的內(nèi)存。相比之下,longSubStr是一個(gè)字符串 ,從子字符串創(chuàng)建時(shí),它有自己的存儲(chǔ)空間。

字符串和子字符串區(qū)別與聯(lián)系

字符串比較:
字符串和字符是否相等的比較:使用“等于”運(yùn)算符==和“不等于”運(yùn)算符!=檢查字符串和字符相等性。

let testStr1 = "i have a cat\u{E9}?"http://!< i have a caté?
let testStr2 = "i have a cat\u{65}\u{301}?"http://!< i have a caté?
if testStr1 == testStr2 {
    print("這兩個(gè)字符串是相等的")
}

如果兩個(gè)字符串值(或兩個(gè)字符值)的擴(kuò)展字形集群在規(guī)范上等效,則它們被認(rèn)為是相等的。如果擴(kuò)展的字形集群具有相同的語(yǔ)言含義和外觀,則它們?cè)谝?guī)范上是等效的,即使它們是不同Unicode標(biāo)量組成的。
舉個(gè)反例:英語(yǔ)中大寫(xiě)字母A:\u{0041}不等同于俄語(yǔ)中的A:\u{0410}。字符在視覺(jué)上相同,但卻不具有相同的語(yǔ)言含義,因此也是不相等的。

let englishA = "\u{0041}"http://!< A
let RussianA = "\u{0410}"http://!< A
if englishA == RussianA {
    print("這兩個(gè)字符串是相等的")
} else {
    print("這兩個(gè)字符串是不相等的")//!< log:這兩個(gè)字符串是不相等的
}

字符串的前綴與后綴的比較:要檢查字符串是否具有特定的字符串前綴或后綴,調(diào)用字符串的hasPrefix(_ :)hasSuffix(_ :)方法,返回值都為布爾值。

let testStr1 = "i have a cat\u{E9}?"http://!< i have a caté?
let testStr2 = "i have a cat\u{65}\u{301}?"http://!< i have a caté?
let array = [testStr1,testStr2]
for item in array[...] {
    if item.hasPrefix("i") {
        print(item + "*")
    }
}
/*注意:hasPrefix(_ :)和hasSuffix(_ :)方法在每個(gè)字符串中的擴(kuò)展字形集群之間執(zhí)行逐個(gè)字符的規(guī)范等效比較。*/
for item in array[...] {
    if item.hasSuffix("\u{E9}?") {
        print(item + "*")//!<輸出兩次: i have a caté?*
    }
}

注意:在每個(gè)字符串中調(diào)用hasPrefix(_ :)hasSuffix(_ :)方法,會(huì)在字符串的擴(kuò)展字形集群之間逐個(gè)字符進(jìn)行規(guī)范的相等比較
字符串的Unicode表示:
將Unicode字符串寫(xiě)入文本文件或其他存儲(chǔ)時(shí),字符串中的Unicode標(biāo)量將以多種Unicode定義的編碼方式之一進(jìn)行編碼。每種編碼方式都是以碼元(二進(jìn)制位)為單位對(duì)字符串進(jìn)行編碼。
Unicode定義的編碼方式:1.UTF-8編碼格式:將字符串編碼為多個(gè)8個(gè)二進(jìn)制位的碼元。2.UTF-16編碼格式:將字符串編碼為多個(gè)16個(gè)二進(jìn)制位的碼元。3.UTF-32編碼格式:將字符串編碼為多個(gè)32個(gè)二進(jìn)制位的碼元。
Swift提供了幾種訪問(wèn)字符串的Unicode的方法。
a. 使用for-in語(yǔ)句迭代字符串,將其各個(gè)字符值作為Unicode擴(kuò)展字符集群進(jìn)行訪問(wèn)。
b. 訪問(wèn)字符串的值依據(jù)兼容Unicode的三種編碼方式之一。

  • UTF-8碼元的集合,使用字符串的utf8屬性訪問(wèn)
  • UTF-16碼元的集合,使用字符串的utf16屬性訪問(wèn)
  • 21位的Unicode標(biāo)量值的集合,相當(dāng)于字符串的UTF-32編碼格式,使用字符串的unicodeScalars屬性訪問(wèn)。

1.UTF-8表示:
通過(guò)迭代字符串的utf8屬性來(lái)訪問(wèn)字符串的UTF-8編碼格式的表示形式。utf8屬性的類(lèi)型為String.UTF8View
關(guān)于String.UTF8View結(jié)構(gòu)體:將字符串內(nèi)容作為UTF-8碼元的集合進(jìn)行展示。我們可以使用字符串utf8屬性訪問(wèn)字符串的UTF-8碼元表示形式。String.UTF8View將字符串的Unicode標(biāo)量值編碼為無(wú)符號(hào)的8位整數(shù),故:String.UTF8View是無(wú)符號(hào)的8位整數(shù)UInt8值的集合 。字符串中Unicode標(biāo)量值最長(zhǎng)可達(dá)21位。要使用8位整數(shù)表示這些標(biāo)量值,通常需要多個(gè)UTF-8代碼單元。

let flowers = "Flowers "
for v in flowers.utf8 {
    print(v,"",separator: " ", terminator: "")//替換換行符
}
//!< 控制臺(tái)最終輸出:70 108 111 119 101 114 115 32 240 159 146 144
/*一個(gè)的字符是unicode標(biāo)量:\u{1F490}
flowermoji.unicodeScalars :32位的0001F490 表示字符為\u{1F490} 打印值為:128144
*/
let flowermoji = "" 
let flowermojiUnicodeScalars = flowermoji.unicodeScalars //!< log:"\u{0001F490}" 這個(gè)是封包了
for v in flowermojiUnicodeScalars {
    print(v,v.value)//!< v.value = 128144  9*16 + 4*256 +15 * 256 *16 + 256 *256 = 128144
}
//將unicode標(biāo)量:\u{128144},轉(zhuǎn)為UTF-8編碼集合,會(huì)發(fā)現(xiàn)需要多個(gè)
var count = 0
var value = ""
for v in flowermoji.utf8 {
    count += 1
    value += "\(v) "
}
//!console.log:unicode標(biāo)量轉(zhuǎn)換成了4個(gè)utf8碼元集合分別是:240 159 146 144
print("\u{1F490}unicode標(biāo)量轉(zhuǎn)換成了\(count)個(gè)utf8碼元集合分別是:\(value)")

比如let dogString = "Dog"轉(zhuǎn)換UTF-8集合"68 111 103 226 128 188 240 159 144 182 "

dogString轉(zhuǎn)換UTF-8集合

2.UTF-16表示:
通過(guò)迭代字符串的utf16屬性來(lái)訪問(wèn)字符串的UTF-16編碼格式的表示形式。utf16屬性的類(lèi)型為String.UTF16View,與String.UTF8View同理。區(qū)別:String.UTF16View是無(wú)符號(hào)的16位整數(shù)UInt16值的集合 。字符串中Unicode標(biāo)量值最長(zhǎng)可達(dá)21位。要使用16位整數(shù)表示這些標(biāo)量值,可能需要兩個(gè)UTF-16代碼單元。

let dogString = "Dog"
var count = 0
var value = ""
for v in dogString.utf16 {
    count += 1
    value += "\(v) "
}
//控制臺(tái)輸出:  unicode標(biāo)量轉(zhuǎn)換成了6個(gè)utf16碼元集合分別是:68 111 103 8252 55357 56374
print("\u{1F436}unicode標(biāo)量轉(zhuǎn)換成了\(count)個(gè)utf16碼元集合分別是:\(value)")//  :\u{1F436}
dogString轉(zhuǎn)換UTF-16集合

3.Unicode Scalar 表示:
通過(guò)迭代字符串的unicodeScalars屬性來(lái)訪問(wèn)字符串的Unicode標(biāo)量表示形式(集合)。unicodeScalars屬性的類(lèi)型為String.UnicodeScalarView。每個(gè)UnicodeScalar都有一個(gè)value屬性: Unicode.Scalar的實(shí)例對(duì)象,會(huì)使用無(wú)符號(hào)的32位整數(shù)UInt32,返回標(biāo)量的值。

for scalar in dogString.unicodeScalars {
    print("\(scalar.value) ", terminator: "")// log "68 111 103 8252 128054 "
}
dogString轉(zhuǎn)換Unicode標(biāo)量的集合

參考資料:
swift 5.1官方編程指南

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

推薦閱讀更多精彩內(nèi)容