由苹果官网翻译得来
fork自https://github.com/letsswift/The-Swift-Programming-Language-in-Chinese
由https://github.com/TyrantDante/The-Swift-Programming-Language-in-Chinese 完善和检查
一个字符串String就是一个字符序列,像”hello,world”,”albatross”这样的。Swift中的字符串是用String关键词来定义的,同时它也是一些字符的集合,用Character定义。
Swift的String和Character类型为代码提供了一个快速的,兼容Unicode的字符解决方案。String类型的初始化和使用都是可读的,并且和C中的strings类似。同时String也可以通过使用+运算符来组合,使用字符串就像使用Swift中的其他基本类型一样简单。
字符串常量
在代码中可以使用由String预先定义的字符串常量,定义方式非常简单:
let someString = “Some string literal value”
字符串常量可以包括下面这些特殊字符:
空字符\0,反斜杠\,制表符\t,换行符\n,回车符\r,双引号\”和单引号\’
单字节Unicode字符,\xnn,其中nn是两个十六进制数
双字节Unicode字符,\unnnn,其中nnnn是四个十六进制数
四字节Unicode字符,\Unnnnnnnn,其中nnnnnnnn是八个十六进制数
下面的代码给出了这四种字符串的例子:
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
初始化一个空串
初始化一个空串时有两种形式,但是两种初始化方法的结果都一样,表示空串
var emptyString = "" // empty string literal
var anotherEmptyString = String() // initializer syntax
// these two strings are both empty, and are equivalent to each other
通过isEmpty属性可以检查一个字符串是否为空
if emptyString.isEmpty {
print("Nothing to see here")
}
// prints "Nothing to see here"
变长字符串
如果使用var关键词定义的字符串即为可修改的变长字符串,而let关键词定义的字符串是常量字符串,不可修改。
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
字符串不是指针,而是实际的值
在Swift中,一个String类型就是一个实际的值,当定义一个新的String,并且将之前的String值拷贝过来的时候,是实际创建了一个相等的新值,而不是仅仅像指针那样指向过去。
同样在函数传递参数的时候,也是传递的实际值,并且创建了一个新的字符串,后续的操作都不会改变原有的String字符串。
字符
Swift的字符串String就是由字符Character组成的,每一个Character都代表了一个特定的Unicode字符。通过for-in循环,可以遍历字符串中的每一个字符:
for character in "Dog!🐶" {
print(character)
}
// D
// o
// g
// !
// 🐶
你也可以仅仅定义一个单独的字符:
let yenSign: Character = "¥"
String 值可以通过传递一个字符数组来初始化
let catCharacters:[Character] = ["C","a","t","!","🐱"]
let catString = String(carCharacters)
print(catString)
//Prints "Cat!🐱"
字符计数
使用全局函数countElements可以计算一个字符串中字符的数量:
let unusualMenagerie = "Koala , Snail , Penguin , Dromedary "
print("unusualMenagerie has \(countElements(unusualMenagerie)) characters")
// prints "unusualMenagerie has 40 characters"
组合使用字符和字符串
String和Character类型可以通过使用+号相加来组合成一个新的字符串
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!"
使用字符串生成新串
通过现有的字符串,可以使用如下方法来生成新的字符串:
let multiplier = 3
let message = "\(multiplier) times 2.5 is \(Double(multiplier) * 2.5)"
// message is "3 times 2.5 is 7.5"
在上面这个例子中,首先使用multiplier这个字符串3,来作为新串的一部分,用(multiplier)添加,同时上面的例子还用到了类型转换Double(multiplier),将计算结果和字符串本身都作为元素添加到了新的字符串中。
大小写字符串
你可以从一个String类型的uppercaseString 和 lowercaseString中获得一个字符串的大写或小写。
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是编码和表示文本的国际标准。它几乎可以显示所有语言的所有字符的标准形态。还可以从类似于文本文件或者网页这样的外部源文件中读取和修改他们的字符。
Unicode术语
每一个Unicode字符都能被编码为一个或多个unicode scalar。一个unicode scalar是一个唯一的21位数(或者名称),对应着一个字符或者标识。例如 U+0061是一个小写的A (“a”), 或者U+1F425是一个面向我们的黄色小鸡
当一个Unicode字符串写入文本或者其他储存时,unicode scalar会根据Unicode定义的格式来编码。每一个格式化编码字符都是小的代码块,称成为code units.他包含UTF-8格式(每一个字符串由8位的code units组成)。和UTF-16格式(每一个字符串由16位的code units组成)
Unicode字符串
Swift 支持多种不同的方式取得Unicode字符串.
你可以使用for-in语句遍历字符串,来获得每一个字符的Unicode编码值。这个过程已经在字符(Working with Characters)描述过了。
或者,下面三个描述中使用合适的一个来获得一个字符串的值
- UTF-8字符编码单元集合使用String类型的utf-8属性
- UTF-16字符编码单元集合使用String类型的utf-16属性
- 21位Unicode标量集合使用String类型的unicodeScalars属性
下面的每一个例子展示了不同编码显示由 D , o , g , !
(DOG FACE, 或者Unicode标量 U+1F436)字符组成的字符串
UTF-8
你可以使用String类型的utf8属性遍历一个UTF-8编码的字符串。这个属性是UTF8View类型
,UTF8View是一个8位无符号整形(UInt8)的集合,集合中的每一个字节都是UTF-8编码。
for codeUnit in dogString.utf8 {
print("\(codeUnit) ")
}
print("\n")
// 68 111 103 33 240 159 144 182
在上面的例子中,前4个十进制codeunit值(68,111,103,33)显示为字符串 D , o ,g 和 ! ,和他们的ASCII编码相同一样。后面4个codeunit的值(240,159,144,182)是DOG FACE字符的4字节UTF-8编码。
UTF-16
你可以使用String类型的utf16属性遍历一个UTF-16编码的字符串。这个属性是UTF16View类型,UTF16View是一个16位无符号整形(UInt16)的集合,集合中的每一个字节都是UTF-16编码。
for codeUnit in dogString.utf16 {
print("\(codeUnit) ")
}
print("\n")
// 68 111 103 33 55357 56374
同理,前4个十进制codeunit值(68,111,103,33)显示为字符串 D , o ,g 和 ! ,他们的UTF-16 的codeunit和他们UTF-8的编码值相同。
第5和第6个codeunit值(55357和56374)是DOG FACE字符的UTF-16的代理对编码。他们的值是由值为U+D83D(十进制55357)的高位代理(lead surrogate)和值为U+DC36 (十进制56374)的低位代理(trail surrogate)组成。
Unicode标量
你可以使用String类型的unicodeScalars属性遍历一个Unicode标量编码的字符串。这个属性是UnicodeScalarsView类型,UnicodeScalarsView是一个UnicodeScalar类型的集合。每一个Unicode标量都是一个任意21位Unicode码位,没有高位代理,也没有低位代理。
每一个UnicodeScalar使用value属性,返回标量的21位值,每一位都是32位无符号整形(UInt32)的值:
for scalar in dogString.unicodeScalars {
print("\(scalar.value) ")
}
print("\n")
// 68 111 103 33 128054
value属性在前4个UnicodeScalar值(68,111,103,33)再一次展示编码了字符 D , o , g 和 ! 。第五个也是最后一个UnicodeScalar 是DOG FACE字符,十进制为128054,等价于16进制的1F436,相当于Unicode标量的U+1F436。
每一个UnicodeScalar可以被构造成一个新的字符串来代替读取他们的value属性,类似于插入字符串。
for scalar in dogString.unicodeScalars { print("\(scalar) ") }
// D
// o
// g
// !
//
访问和修改string
我们可以通过string的方法和属性来访问和修改string,或者下目标语法
string目录
每个string值都一个序列,string.index。他可以用来定位string中的每一个字符
不同的字符占用了不同的内存,为了确定每个字符所在的位置,你必须从string的开头或结尾�遍历每个unicode数量。基于这么原因,swift string不能被integer定位。
使用startIndex属性来访问string中的第一个位置的字符。用endIndex是string中最后一个字符的后面。所以,endIndex不是一个有效的下标参数。如果string为空,那么startIndex和endIndex是一样的。
String.Index可以使用 predecessor()来获取前一个标签,successor()来获取下一标签。String中的index可以通过方法从别的index获取。或使用advanceBy(_:)。如果超出了访问一个string外的index会抛出一个运行时错误。
可以通过下标来访问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
尝试访问一个string范围以外的index,会抛出运行时错误
greeting[greeting.endIndex] //error
greeting.endIndex.successor() //error
使用characters的indices来创建每个indexes的rang,然后对他们都转成string输出
for index in greeting.characters.indices {
print("\(greeting[index])",terminator:"")
}
//prints "G u t e n T a g ! "
插入和删除
对string在一个特定的位置插入一个字符,使用 inset(_:atIndex:)方法
var welcome = "hello"
welcome.insert("!",atIndex:welcome.endIndex)
// welcome now equals "hello!"
对string在一个特定的位置插入另一个string的全部内容,使用 insertContentsOf(_:at:)方法
welcome.insetContentsOf(" there".characters , at:welcome.endIndex.predecessor())
// welcome now equals "hello there!"
删除string的一个特定位置的字符,使用 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提供三种方法比较字符串的值:字符串相等,前缀相等,和后缀相等
字符串相等
当两个字符串的包含完全相同的字符时,他们被判断为相等。
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 类的两个方法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 方法和romeoAndJuliet数组 计算出第一幕要表演多少个场景。
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 方法去计算有多少个场景发生在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”