# Swift中文教程(三) 字符串和字符

由蘋果官網(wǎng)翻譯得來
fork自https://github.com/letsswift/The-Swift-Programming-Language-in-Chinese
https://github.com/TyrantDante/The-Swift-Programming-Language-in-Chinese 完善和檢查

一個(gè)字符串String就是一個(gè)字符序列,像”hello,world”,”albatross”這樣的。Swift中的字符串是用String關(guān)鍵詞來定義的,同時(shí)它也是一些字符的集合,用Character定義。

Swift的String和Character類型為代碼提供了一個(gè)快速的,兼容Unicode的字符解決方案。String類型的初始化和使用都是可讀的,并且和C中的strings類似。同時(shí)String也可以通過使用+運(yùn)算符來組合,使用字符串就像使用Swift中的其他基本類型一樣簡單。

字符串常量

在代碼中可以使用由String預(yù)先定義的字符串常量,定義方式非常簡單:

let someString = “Some string literal value”

字符串常量可以包括下面這些特殊字符:

  • 空字符\0,反斜杠\,制表符\t,換行符\n,回車符\r,雙引號\”和單引號\’

  • 單字節(jié)Unicode字符,\xnn,其中nn是兩個(gè)十六進(jìn)制數(shù)

  • 雙字節(jié)Unicode字符,\unnnn,其中nnnn是四個(gè)十六進(jìn)制數(shù)

  • 四字節(jié)Unicode字符,\Unnnnnnnn,其中nnnnnnnn是八個(gè)十六進(jìn)制數(shù)

下面的代碼給出了這四種字符串的例子:

let wiseWords = "\"Imagination is more important than knowledge\" - Einstein"
// "Imagination is more important than knowledge" - Einstein
let dollarSign = "\x24" // $, Unicode scalar U+0024
let blackHeart = "\u2665" // ?, Unicode scalar U+2665
let sparklingHeart = "\U0001F496" // , Unicode scalar U+1F496

初始化一個(gè)空串

初始化一個(gè)空串時(shí)有兩種形式,但是兩種初始化方法的結(jié)果都一樣,表示空串

var emptyString = "" // empty string literal
var anotherEmptyString = String() // initializer syntax
// these two strings are both empty, and are equivalent to each other

通過isEmpty屬性可以檢查一個(gè)字符串是否為空

if emptyString.isEmpty {
    print("Nothing to see here")
}
// prints "Nothing to see here"

變長字符串

如果使用var關(guān)鍵詞定義的字符串即為可修改的變長字符串,而let關(guān)鍵詞定義的字符串是常量字符串,不可修改。

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

字符串不是指針,而是實(shí)際的值

在Swift中,一個(gè)String類型就是一個(gè)實(shí)際的值,當(dāng)定義一個(gè)新的String,并且將之前的String值拷貝過來的時(shí)候,是實(shí)際創(chuàng)建了一個(gè)相等的新值,而不是僅僅像指針那樣指向過去。

同樣在函數(shù)傳遞參數(shù)的時(shí)候,也是傳遞的實(shí)際值,并且創(chuàng)建了一個(gè)新的字符串,后續(xù)的操作都不會改變原有的String字符串。

字符

Swift的字符串String就是由字符Character組成的,每一個(gè)Character都代表了一個(gè)特定的Unicode字符。通過for-in循環(huán),可以遍歷字符串中的每一個(gè)字符:

for character in "Dog!??" {
    print(character)
}
// D
// o
// g
// !
// ??

你也可以僅僅定義一個(gè)單獨(dú)的字符:

let yenSign: Character = "¥"

String 值可以通過傳遞一個(gè)字符數(shù)組來初始化

let catCharacters:[Character] = ["C","a","t","!","??"]
let catString = String(carCharacters)
print(catString)
//Prints "Cat!??"

字符計(jì)數(shù)

使用全局函數(shù)countElements可以計(jì)算一個(gè)字符串中字符的數(shù)量:

let unusualMenagerie = "Koala , Snail , Penguin , Dromedary "
print("unusualMenagerie has \(countElements(unusualMenagerie)) characters")
// prints "unusualMenagerie has 40 characters"

組合使用字符和字符串

String和Character類型可以通過使用+號相加來組合成一個(gè)新的字符串

let string1 = "hello"
let string2 = " there"
let character1: Character = "!"
let character2: Character = "?"
let stringPlusCharacter = string1 + character1 // equals "hello!"
let stringPlusString = string1 + string2 // equals "hello there"
let characterPlusString = character1 + string1 // equals "!hello"
let characterPlusCharacter = character1 + character2 // equals "!?"

也可以使用+=號來組合:

var instruction = "look over"
instruction += string2
// instruction now equals "look over there"
var welcome = "good morning"
welcome += character1
// welcome now equals "good morning!"

使用字符串生成新串

通過現(xiàn)有的字符串,可以使用如下方法來生成新的字符串:

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

在上面這個(gè)例子中,首先使用multiplier這個(gè)字符串3,來作為新串的一部分,用(multiplier)添加,同時(shí)上面的例子還用到了類型轉(zhuǎn)換Double(multiplier),將計(jì)算結(jié)果和字符串本身都作為元素添加到了新的字符串中。

大小寫字符串

你可以從一個(gè)String類型的uppercaseString 和 lowercaseString中獲得一個(gè)字符串的大寫或小寫。

let normal = "Could you help me, please?"
let shouty = normal.uppercaseString
// shouty is equal to "COULD YOU HELP ME, PLEASE?"
let whispered = normal.lowercaseString
// whispered is equal to "could you help me, please?"

Unicode

Unicode是編碼和表示文本的國際標(biāo)準(zhǔn)。它幾乎可以顯示所有語言的所有字符的標(biāo)準(zhǔn)形態(tài)。還可以從類似于文本文件或者網(wǎng)頁這樣的外部源文件中讀取和修改他們的字符。

Unicode術(shù)語

每一個(gè)Unicode字符都能被編碼為一個(gè)或多個(gè)unicode scalar。一個(gè)unicode scalar是一個(gè)唯一的21位數(shù)(或者名稱),對應(yīng)著一個(gè)字符或者標(biāo)識。例如 U+0061是一個(gè)小寫的A (“a”), 或者U+1F425是一個(gè)面向我們的黃色小雞

當(dāng)一個(gè)Unicode字符串寫入文本或者其他儲存時(shí),unicode scalar會根據(jù)Unicode定義的格式來編碼。每一個(gè)格式化編碼字符都是小的代碼塊,稱成為code units.他包含UTF-8格式(每一個(gè)字符串由8位的code units組成)。和UTF-16格式(每一個(gè)字符串由16位的code units組成)

Unicode字符串

Swift 支持多種不同的方式取得Unicode字符串.

你可以使用for-in語句遍歷字符串,來獲得每一個(gè)字符的Unicode編碼值。這個(gè)過程已經(jīng)在字符(Working with Characters)描述過了。

或者,下面三個(gè)描述中使用合適的一個(gè)來獲得一個(gè)字符串的值

  • UTF-8字符編碼單元集合使用String類型的utf-8屬性
  • UTF-16字符編碼單元集合使用String類型的utf-16屬性
  • 21位Unicode標(biāo)量集合使用String類型的unicodeScalars屬性

下面的每一個(gè)例子展示了不同編碼顯示由 D , o , g , !

(DOG FACE, 或者Unicode標(biāo)量 U+1F436)字符組成的字符串

UTF-8

你可以使用String類型的utf8屬性遍歷一個(gè)UTF-8編碼的字符串。這個(gè)屬性是UTF8View類型
,UTF8View是一個(gè)8位無符號整形(UInt8)的集合,集合中的每一個(gè)字節(jié)都是UTF-8編碼。

for codeUnit in dogString.utf8 {
    print("\(codeUnit) ")
}
print("\n")
// 68 111 103 33 240 159 144 182

在上面的例子中,前4個(gè)十進(jìn)制codeunit值(68,111,103,33)顯示為字符串 D , o ,g 和 ! ,和他們的ASCII編碼相同一樣。后面4個(gè)codeunit的值(240,159,144,182)是DOG FACE字符的4字節(jié)UTF-8編碼。

UTF-16

你可以使用String類型的utf16屬性遍歷一個(gè)UTF-16編碼的字符串。這個(gè)屬性是UTF16View類型,UTF16View是一個(gè)16位無符號整形(UInt16)的集合,集合中的每一個(gè)字節(jié)都是UTF-16編碼。

for codeUnit in dogString.utf16 {
    print("\(codeUnit) ")
}
print("\n")
// 68 111 103 33 55357 56374

同理,前4個(gè)十進(jìn)制codeunit值(68,111,103,33)顯示為字符串 D , o ,g 和 ! ,他們的UTF-16 的codeunit和他們UTF-8的編碼值相同。

第5和第6個(gè)codeunit值(55357和56374)是DOG FACE字符的UTF-16的代理對編碼。他們的值是由值為U+D83D(十進(jìn)制55357)的高位代理(lead surrogate)和值為U+DC36 (十進(jìn)制56374)的低位代理(trail surrogate)組成。

Unicode標(biāo)量

你可以使用String類型的unicodeScalars屬性遍歷一個(gè)Unicode標(biāo)量編碼的字符串。這個(gè)屬性是UnicodeScalarsView類型,UnicodeScalarsView是一個(gè)UnicodeScalar類型的集合。每一個(gè)Unicode標(biāo)量都是一個(gè)任意21位Unicode碼位,沒有高位代理,也沒有低位代理。

每一個(gè)UnicodeScalar使用value屬性,返回標(biāo)量的21位值,每一位都是32位無符號整形(UInt32)的值:

for scalar in dogString.unicodeScalars {
    print("\(scalar.value) ")
}
print("\n")
// 68 111 103 33 128054

value屬性在前4個(gè)UnicodeScalar值(68,111,103,33)再一次展示編碼了字符 D , o , g 和 ! 。第五個(gè)也是最后一個(gè)UnicodeScalar 是DOG FACE字符,十進(jìn)制為128054,等價(jià)于16進(jìn)制的1F436,相當(dāng)于Unicode標(biāo)量的U+1F436。

每一個(gè)UnicodeScalar可以被構(gòu)造成一個(gè)新的字符串來代替讀取他們的value屬性,類似于插入字符串。

for scalar in dogString.unicodeScalars { print("\(scalar) ") }
// D
// o
// g
// !
//

訪問和修改string

我們可以通過string的方法和屬性來訪問和修改string,或者下目標(biāo)語法

string目錄

每個(gè)string值都一個(gè)序列,string.index。他可以用來定位string中的每一個(gè)字符

不同的字符占用了不同的內(nèi)存,為了確定每個(gè)字符所在的位置,你必須從string的開頭或結(jié)尾?遍歷每個(gè)unicode數(shù)量?;谶@么原因,swift string不能被integer定位。

使用startIndex屬性來訪問string中的第一個(gè)位置的字符。用endIndex是string中最后一個(gè)字符的后面。所以,endIndex不是一個(gè)有效的下標(biāo)參數(shù)。如果string為空,那么startIndex和endIndex是一樣的。

String.Index可以使用 predecessor()來獲取前一個(gè)標(biāo)簽,successor()來獲取下一標(biāo)簽。String中的index可以通過方法從別的index獲取。或使用advanceBy(_:)。如果超出了訪問一個(gè)string外的index會拋出一個(gè)運(yùn)行時(shí)錯誤。

可以通過下標(biāo)來訪問string中特定的index來獲取字符

let greeting = "Guten Tag!"
greeting[greeting.startIndex]
//G
greeting[greeting.endIndex.predecessor()]
//!
greeting[greeting.start.successor()]
//u
let index = greeting.startIndex.advanceBy(7)
greeting[index]
//a

嘗試訪問一個(gè)string范圍以外的index,會拋出運(yùn)行時(shí)錯誤
greeting[greeting.endIndex] //error
greeting.endIndex.successor() //error

使用characters的indices來創(chuàng)建每個(gè)indexes的rang,然后對他們都轉(zhuǎn)成string輸出

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

插入和刪除

對string在一個(gè)特定的位置插入一個(gè)字符,使用 inset(_:atIndex:)方法

var welcome = "hello"
welcome.insert("!",atIndex:welcome.endIndex)
// welcome now equals "hello!"

對string在一個(gè)特定的位置插入另一個(gè)string的全部內(nèi)容,使用 insertContentsOf(_:at:)方法

welcome.insetContentsOf(" there".characters , at:welcome.endIndex.predecessor())
// welcome now equals "hello there!"

刪除string的一個(gè)特定位置的字符,使用 removeAtIndex(_:)方法

welcome.removeAtIndex(welcome.endIndex.predecessor())
//welcome now equals "hello there"

對于string的特定范圍刪除,使用removeRange(_:)方法

let rang = welcome.endIndex.advancedBy(-6)..<welcome.endIndex
welcome.removeRange(range)
//welcome now equals "hello"

字符串比較

Swift提供三種方法比較字符串的值:字符串相等,前綴相等,和后綴相等

字符串相等

當(dāng)兩個(gè)字符串的包含完全相同的字符時(shí),他們被判斷為相等。

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"
//輸出”These two strings are considered equal”

前綴(prefix)相等和后綴(hasSuffix)相等

使用string 類的兩個(gè)方法hasPrefix和hasSuffix,來檢查一個(gè)字符串的前綴或者后綴是否包含另外一個(gè)字符串,它需要一個(gè)String類型型的參數(shù)以及返回一個(gè)布爾類型的值。兩個(gè)方法都會在原始字符串和前綴字符串或者后綴字符串之間做字符與字符之間的。

下面一個(gè)例子中,用一個(gè)字符串?dāng)?shù)組再現(xiàn)了莎士比亞的羅密歐與朱麗葉前兩幕的場景。

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 方法和romeoAndJuliet數(shù)組 計(jì)算出第一幕要表演多少個(gè)場景。

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

同理,使用hasSuffix 方法去計(jì)算有多少個(gè)場景發(fā)生在Capulet公館和Friar Lawrence牢房

var mansionCount = 0
var cellCount = 0
for scene in romeoAndJuliet {
    if scene.hasSuffix("Capulet's mansion") {
        ++mansionCount
    } else if scene.hasSuffix("Friar Lawrence's cell") {
        ++cellCount
    }
}
print("\(mansionCount) mansion scenes; \(cellCount) cell scenes")
// 輸出 "6 mansion scenes; 2 cell scenes”
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容