Swift 3 學習 - 03 字符串和字符

Swift 3.png
  • 1 .字符串字面量 String

在Swift中字符串字面量是由雙引號" " 包裹著的

let someString = "Some string literal value"

像我們在 Swift 3 學習 01 中講述的那樣,Swift 會推斷該常量為String類型

  • 2 .初始化空字符串
    • 2.1 初始化

創(chuàng)建一個空字符串的兩種方式

//(1)可以將空的字符串字面量賦值給變量
var emptyString = "" // empty string literal
//(2)初始化一個新的String實例
var anotherEmptyString = String() // initializer syntax
// these two strings are both empty, and are equivalent to each other
    • 2.2 判斷空字符串

isEmpty 屬性來判斷該字符串是否為空,返回值為 Bool

var emptyString = ""
if emptyString.isEmpty {
print("Nothing to see here")
}
// Prints "Nothing to see here"
  • 3 .字符串可變性

在 Objective-C 中,需要通過選擇兩個不同的類(NSString和NSMutableString)來指定字符串是否可以被修改。而在Swift中用 let 聲明常量來保證其不會被修改,用 var聲明變量來對其進行修改。

//可變的字符串
var variableString = "Horse"
variableString += " and carriage"
// variableString is now "Horse and carriage"
//不可變的字符串
let constantString = "Highlander"
constantString += " and another Highlander"
// this reports a compile-time error - a constant string cannot be modified
3.0.png
  • 4 .字符串是值類型

Swift 的 String 類型是值類型。 如果創(chuàng)建了一個新的字符串,那么當其進行常量、變量賦值操作,或在函數/方法中傳遞時,會進行值拷貝。
這樣做的好處是,你可以確信傳遞的字符串不會被修改,除非你自己去修改它。
在 Objective-C 中,你可能面臨著值被 '別人' 修改的風險,比如下面的 a .你并沒有去直接修改ta.

NSString * a;
NSMutableString * b = [@"111111" mutableCopy];
 a = b;
 [b appendString:@"222222"];
 NSLog(@"a = %@",a); //a = 111111222222

在Swift中,無論怎樣都不會將你的 a 修改 ,除非你直接對 a 進行修改。

var a : String;
var b = "111111"
a = b;
b = b.appending("222222");
print("a = \\(a)\\n")          //輸出的 a = 111111
  • 5 . 使用字符 Character
    • 5.1 獲取字符串的字符

通過for-in循環(huán)來遍歷字符串中的characters屬性來獲取每一個字符的值.

for character in "Dog!".characters {
print(character)
}
// D
// o
// g
// !
// 
    • 5.2 聲明一個字符

通過Character 關鍵字聲明一個字符

let exclamationMark2: Character = "!"

必須要用Character聲明才能得到一個字符,否則會被Swift推斷為String類型。

5.2.png

    • 5.3 用字符數組初始化一個字符串

字符串可以通過傳遞一個值類型為Character的數組作為自變量來初始化。

let catCharacters: [Character] = ["C", "a", "t", "!", ""]
let catString = String(catCharacters)
print(catString)
// Prints "Cat!"
  • 6 .連接字符串和字符 ++=append()

你可以不追加StringCharacter到現(xiàn)有的Character變量,因為一個Character值必須只包含一個字符。

    • 6.1 +

字符串可以通過加法運算符(+)相加在一起(或稱“連接”)創(chuàng)建一個新的字符串,在前面的文章提及過。

let string1 = "hello"
let string2 = " there"
var welcome = string1 + string2
// welcome now equals "hello there"
    • 6.2 +=

可以通過加法賦值運算符 (+=) 將一個字符串添加到一個已經存在字符串變量上

var instruction = "look over"
instruction += string2
// instruction now equals "look over there
    • 6.3 append()

可以用append()方法將一個字符附加到一個字符串變量的尾部

let exclamationMark: Character = "!"
welcome.append(exclamationMark)
// welcome now equals "hello there!"
  • 7 .字符串插值 \\(a)

Swift提供便利的方式在字符串中插入一些值。a可以是常量、變量、字面量和表達式。 插入的字符串字面量的每一項都在以反斜線為前綴的圓括號中 即 \\(a)

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

在上述代碼中 \\(multiplier) 做為整體插入到字符串中,在系統(tǒng)讀取時會將對應的值插入該位置。

  • 8 .Unicode

Unicode 是一個國際標準,用于文本的編碼和表示。Swift 的String和Character類型是完全兼容 Unicode 標準的。

    • 8.1 Unicode 標量

Swift 的String類型是基于 Unicode 標量 建立的。 Unicode 標量是對應字符或者修飾符的唯一的21位數字,例如U+0061表示小寫的拉丁字母("a"),U+1F425表示小雞表情("")。
Unicode 碼位的范圍是U+0000U+D7FF或者U+E000U+10FFFF。Unicode 標量不包括 Unicode 代理項(surrogate pair) 碼位,其碼位范圍是U+D800U+DFFF

    • 8.2 字符串字面量的特殊字符
      字符串字面量可以包含以下特殊字符:
      轉義字符\\0(空字符)、\\\\\\\\(反斜線)、\\t(水平制表符)、\\n(換行符)、\\r(回車符)、\\"(雙引號)、\\'(單引號)。
      Unicode 標量,寫成\\u{n}(u為小寫),其中n為任意一到八位十六進制數且可用的 Unicode 位碼。
let wiseWords = "\\"Imagination is more important than knowledge\\" - Einstein"
// "Imagination is more important than knowledge" - Einstein
let dollarSign = "\\u{24}" // $, Unicode scalar U+0024
let blackHeart = "\\u{2665}" // , Unicode scalar U+2665
let sparklingHeart = "\\u{1F496}" // , Unicode scalar U+1F496
  • 9 .計算字符數量 count

使用字符串的 characters 屬性的 count 屬性獲取字符數量。

let unusualMenagerie = "Koala , Snail , Penguin , Dromedary "  //只占一個字符。
print("unusualMenagerie has \\(unusualMenagerie.characters.count) characters")
// Prints "unusualMenagerie has 40 characters"
  • 10 .可擴展的字形群集

每一個 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轉換成了é
簡單而言 e (U+0065) + U+0301 --> é(U+00E9)eAcutecombinedEAcute等價

let eAcute: Character = "\\u{E9}" // é
let combinedEAcute: Character = "\\u{65}\\u{301}" // e followed by ?
// eAcute is é, combinedEAcute is é

再比如在韓文中,下面的precomposeddecomposed等價

let precomposed: Character = "\\u{D55C}" // ?
let decomposed: Character = "\\u{1112}\\u{1161}\\u{11AB}" // ?, ?, ?
// precomposed is ?, decomposed is ?

再比如地域性指示符號的 Unicode 標量可以組合成一個單一的Character值

let regionalIndicatorForUS: Character = "\\u{1F1FA}\\u{1F1F8}"
// regionalIndicatorForUS is 
  • 11 .計算字符數量 count

通過characters屬性count屬性獲取字符數量, Swift 中的字符在一個字符串中并不一定占用相同的內存空間數量。另外需要注意的是通過characters屬性返回的字符數量并不總是與包含相同字符的NSString的length屬性相同。NSString的length屬性是利用 UTF-16 表示的十六位代碼單元數字,而不是 Unicode 可擴展的字符群集。當一個Swift的String值 被NSString的length屬性訪問時,字符數量和字符串長度是不一樣的。

let unusualMenagerie = "Koala , Snail , Penguin , Dromedary "
print("unusualMenagerie has \\(unusualMenagerie.characters.count) characters")   
// Prints "unusualMenagerie has 40 characters"
//下面的代碼作為字符串算長度
var  str : NSString;
str = unusualMenagerie as NSString ;
print("str.length = \\(str.length)");    //str.length = 44
  • 12 . 字符串索引

每一個String值都有一個關聯(lián)的索引(index)類型,String.Index,它對應著字符串中的每一個Character的位置。
前面提到,不同的字符可能會占用不同數量的內存空間,所以要知道Character的確定位置,就必須從String開頭遍歷每一個 Unicode 標量直到結尾。因為整數(integer)是內存空間的概念,不同的字符可能會占用不同數量的內存空間,Swift 的字符串不能用整數(integer)做索引。
使用startIndex屬性可以獲取一個String的第一個Character的索引。使用endIndex屬性可以獲取最后一個Character的后一個位置的索引。因此,endIndex屬性不能作為一個字符串的有效下標。如果String是空串,startIndexendIndex是相等的。
通過調用 String 的 index(before:)index(after:)方法,可以立即得到前面或后面的一個索引。您還可以通過調用index(_:offsetBy:)方法來獲取對應偏移量的索引,這種方式可以避免多次調用index(before:)index(after:) 方法。

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,將引發(fā)一個運行時錯誤
fatal error: Can't form a Character from an empty String

greeting[greeting.endIndex] // error
greeting.index(after: endIndex) // error

使用 characters 屬性的 indices 屬性會創(chuàng)建一個包含全部索引的范圍(Range),用來在一個字符串中訪問單個字符。

for index in greeting.characters.indices {
print("\\(greeting[index]) ", terminator: "")
}
// Prints "G u t e n T a g ! "
  • 13 .插入

調用insert(_:atIndex:)方法可以在一個字符串的指定索引插入一個字符,調用 insert(contentsOf:at:) 方法可以在一個字符串的指定索引插入一段字符串。(用在遵循Collection協(xié)議的類型)

var welcome = "hello"
welcome.insert("!", at: welcome.endIndex)
// welcome now equals "hello!"
welcome.insert(contentsOf:" there".characters, at: welcome.index(before: welcome.endIndex))
// welcome now equals "hello there!"
  • 14 .刪除

調用 remove(at:) 方法可以在一個字符串的指定索引刪除一個字符,調用 removeSubrange(_:) 方法可以在一個字符串的指定索引刪除一個子字符串。(用在遵循RangeReplaceableCollection協(xié)議的類型)

welcome.remove(at: welcome.index(before: welcome.endIndex))
// welcome now equals "hello there"
let range = welcome.index(welcome.endIndex, offsetBy: -6)..<welcome.endIndex
welcome.removeSubrange(range)
// welcome now equals "hello"
  • 15 .比較字符串

Swift 提供了三種方式來比較文本值:字符串字符相等、前綴相等和后綴相等

    • 15.1 字符串/字符相等

字符串/字符可以用等于操作符(==)和不等于操作符(!=)

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")
}
// Prints "These two strings are considered equal"

如果兩個字符串(或者兩個字符)的可擴展的字形群集是標準相等的,那就認為它們是相等的。在這個情況下,即使可擴展的字形群集是有不同的 Unicode 標量構成的,只要它們有同樣的語言意義和外觀,就認為它們標準相等。
像上面提到的 e (U+0065) + U+0301 --> é(U+00E9)
這兩個字符群集都是表示字符é的有效方式,所以它們被認為是標準相等。

// "Voulez-vous un café?" using LATIN SMALL LETTER E WITH ACUTE
let eAcuteQuestion = "Voulez-vous un caf\\u{E9}?"
// "Voulez-vous un café?" using 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")
}
// Prints "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.")
}
// Prints "These two characters are not equivalent."
    • 15.2 前綴/后綴相等

通過調用字符串的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(_:),如下統(tǒng)計由Act 1開頭的字符串

var act1SceneCount = 0
for scene in romeoAndJuliet {
if scene.hasPrefix("Act 1 ") {
act1SceneCount += 1
}
}
print("There are \\(act1SceneCount) scenes in Act 1")
// Prints "There are 5 scenes in Act 1"

后綴 hasSuffix(_:),如下統(tǒng)計由Capulet's mansion結尾的字符串

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")
// Prints "6 mansion scenes; 2 cell scenes"
  • 16 .字符串的 Unicode 表示形式

UTF-8 : 通過遍歷String的utf8屬性來訪問它的UTF-8表示
UTF-16 : 通過遍歷String的utf16屬性來訪問它的UTF-16表示

UTF-32: 遍歷String值的unicodeScalars屬性來訪問它的 Unicode 標量表示

let dogString = "Dog"
//UTF-8
for codeUnit in dogString.utf8 {
print("\\(codeUnit) ", terminator: "")
}
print("")
//UTF-16
for codeUnit in dogString.utf16 {
print("\\(codeUnit) ", terminator: "")
}
print("")
//UTF-32
for scalar in dogString.unicodeScalars {
print("\\(scalar.value) ", terminator: "")
}
print("")

Character | UTF-8 Code Unit | UTF-16 Code Unit |UTF-32 Code Unit |Position
----|------|----|----|----|---
D(U+0044) | 68|68|68|0
o(U+006F )| 111|111|111|1
g(U+0067)| 103|103|103|2

還是直接上圖吧,官方圖哈哈

UTF8_2x.png

UTF16_2x.png
UnicodeScalar_2x.png

以上只是一些簡單的概念說(fan)明(yi),如有錯誤請指正,謝謝。Swift 3 學習 ,后續(xù)會不斷更新。
如果你覺得我的文章對你有幫助請點喜歡哦,也可以關注我,每周至少一篇技術更新。
或者關注 我的專題 每周至少5篇高質量文章收錄,多謝支持。

一起學習,一起進步

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

推薦閱讀更多精彩內容