开发者社区> joe.huang> 正文

Swift语言指南(十)--字符串与字符

简介: 字符串是一段字符的有序集合,如"hellow,world"或"信天翁"。Swift 中的字符串由 String 类型表示,对应着 Character 类型值的集合。 Swift 中的 String 类型为你的编程提供了一个高速的,兼容 Unicode规范 的文本处理方式。
+关注继续查看

字符串是一段字符的有序集合,如"hellow,world"或"信天翁"。Swift 中的字符串由 String 类型表示,对应着 Character 类型值的集合。

Swift 中的 String 类型为你的编程提供了一个高速的,兼容 Unicode规范 的文本处理方式。Swift 创建和处理字符串的语法轻量可读,与 C 语言的字符串语法颇为相似。字符串的拼接非常简单,只需将两个字符串用 + 运算符相加。字符串的值是否可变取决于其为常量还是变量,这一点与 Swift 中的其它类型一致。

Swift 的 String 类型除了语法简洁之外,还是一个高速,现代化的字符串实现方案。每个字符串均由编码独立的 Unicode 字符组成,每个字符均支持以不同的 Unicode 表达形式访问。

Swift 的字符串还支持在较长的字符串中插入常量、变量、字面量以及表达式的值,该过程称为字符串插入。这使得显示、存储以及输出自定义的字符串值更加简便。

注:

Swift 的 String 类型与底层 Foundation 的 NSString 类无缝衔接。如果你在 Cocoa / Cocoa Touch 中使用 Foundation 框架,那么,除了本章提到的 String 特性之外,对创建的任何 String 值,均可调用到 NSString 类的全部 API。还可以将 String 值传递给任何需要 NSString 实例的 API 方法。

更多 String 与 Foundation / Cocoa 框架结合使用的信息,请见 Swift 与 Cocoa 及 Objective-C 的结合(这一部分内容在本书之外,译完本书再译)

 

字符串字面量

代码中可以在预先定义的 String 值中嵌入字符串字面量string literal)。字符串字面量是由一对双引号("")包围的文本字符的固定序列。

字符串字面量可以为一个常量或变量提供初始值:

let someString = "Some string literal value"

注意,Swift 推断常量 someStringString 类型,因为 someString 的值被一个字符串字面量初始化了。

字符串字面量涵盖了下述特殊字符:

· 转义过的特殊字符: \0(null 字符),\\ (反斜杠,转义后应为单斜杠--Joe.Huang),\t(水平制表符),\n(换行符),\r(回车符),\"(双引号)以及 \'(单引号)

· 单字节的 Unicode 标量,写作 \xnn,其中 nn 为两个十六进制数位

· 双字节的 Unicode 标量,写作 \unnnn,其中 nnnn 为四个十六进制数位

· 四字节的 Unicode 标量,写作 \Unnnnnnnn,其中 nnnnnnnn 为八个十六进制数位

下面的代码展示了这几种特殊字符的例子。常量 wiseWords 包含两个转义后的双引号字符。常量 dollarSignblackHeart 以及 sparklingHeart 展示了 Unicode 标量字符的三种不同书写格式:

let wiseWords = "\"Imagination is more important than knowledge\" - Einstein"
// "Imagination is more important than knowledge" - Einstein
// 输出 "想象力比知识更重要" - 爱因斯坦
let dollarSign = "\x24"        // 输出 $,  Unicode 标量 U+0024
let blackHeart = "\u2665"      // 输出 ,  Unicode 标量 U+2665
let sparklingHeart = "\U0001F496"  // 输出 , Unicode 标量 U+1F496

 

初始化一个空字符串

创建一个较长的字符串,第一步,需要创建一个空的 String 值,你既可以将空字符串字面量赋值给一个变量,也可以用初始化语法初始化一个新的 String 实例:

1 var emptyString = ""               // 空字符串字面量
2 var anotherEmptyString = String()  // 初始化语法
3 // 这两个字符串对象都是空值, 互相等同

你可以使用 isEmpty 属性检测字符串的值是否为空:

1 if emptyString.isEmpty {
2     println("Nothing to see here")
3 }
4 // 输出 "什么都没看到"

 

字符串的可变性

一个特定 String 的值是否可以修改(即可变mutable),可通过声明将其赋值给一个变量(可以修改)或常量(不可修改):

1 var variableString = "Horse"
2 variableString += " and carriage"
3 // variableString 的值现在为 "Horse and carriage"
4  
5 let constantString = "Highlander"
6 constantString += " and another Highlander"
7 // 编译错误 - 常量 string 的值不可更改

注:

该实现方案与 Objective-C / Cocoa 的字符串可变性有所不同,后者是通过在实例所属的两个类中二选一(NSStringNSMutableString)来声明字符串是否可变。

 

String属于传值类型

Swift 的 String 类型是一种传值类型value type。如果将一个 String 值传递给一个函数或方法,或将其赋值给一个常量或变量,则该 String 值也会被一同复制copied过去。这两种情况均会为现有 String 值创建新的副本,实际传递或赋值的是其副本,而非其原始实例。传值类型的说明请见 结构与枚举类型均为传值类型 (后面章节译到)

注:

该行为与 CocoaNSString 不同。Cocoa 中创建 NSString 实例并传递给函数或方法,或赋值给变量时,实际传递或赋值的是同一个 NSString 实例的引用(reference,非复制--copy)。这中间不会有复制字符串的操作,除非特别指定。

Swift 中 String 的 “默认复制” 行为可确保函数或方法传递 String 值给你时,这个 String 值的确属于你,而与其出处无关。可以肯定的是,除非你自己去修改它,你接收到的字符串绝对不会变。

在后台,Swift 的编译器会优化字符串的内存占用,仅在绝对需要时才会实际创建字符串的副本。因此,字符串属于传值类型让你的代码总能达到最佳性能。

 

字符操作

Swift中的 String 类型是一段 Character 值的有序集合,每一个 Character 值代表一个 Unicode 字符。你可以通过 for-in 循环遍历访问一个字符串中的每个 Character 值:

1 for character in "Dog!" {
2     println(character)  //输出(character)
3 }
4 // D
5 // o
6 // g
7 // !
8 // 

For-in 的用法后面在流程控制一章会译到。

另外,通过 Character 类型说明可以从单字符的字符串字面量中单独创建字符常量或变量:

1 let yenSign: Character = "¥"
2 // 指定了yenSign为 Character 类型 -- Joe.Huang

 

字符统计

可以使用全局方法 countElements 来统计字符串中字符的个数,把字符串作为唯一的参数传进即可:

1 let unusualMenagerie = "Koala , Snail , Penguin , Dromedary "
2 println("unusualMenagerie has \(countElements(unusualMenagerie)) characters")
3 // 输出 "unusualMenagerie 有 40 个字符"

注:

不同的 Unicode 字符,以及同一个 Unicode 字符的不同表示,在内存中所占用的存储空间不同。因此,要想计算出字符串的长度,必须遍历整个字符串,依次统计每一个字符。如果你在处理特别长的字符串值,要谨记,countElements 函数需要遍历字符串中的每个字符方能求出其精确的字符个数。

还要注意的一点是,countElements 返回的字符个数,与包含同样字符的 NSString 对象的 length 属性所返回的字符个数并不总是一样多。NSString 的长度根据该字符串的 UTF-16 形式的 16 位码单元个数得出,而非根据字符串内 Unicode 字符的个数得出。为了区别体现这一事实,在 Swift 语言中,NSStringlength 属性需通过 String 值的 utf16count 属性访问。

 

字符串与字符的拼接

StringCharacter 值可以用加法运算符(+)加在一起(即连接concatenate),得到一个新的 String 值:

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

(接上例的常量)还可以用加法赋值运算符(+=)在 String 变量的末尾追加(append) String 或 Character

var instruction = "look over"
instruction += string2
// instruction now equals "look over there"
// instruction 现在等于 "瞧那儿"
 
var welcome = "good morning"
welcome += character1
// welcome now equals "good morning!"
// welcome 现在等于 "早上好!"

 

字符串插入

字符串插入是一种将常量,变量,字面量,表达式混合插入字符串字面量并得到一个新的 String 值的方法。字符串字面量中插入的每一项均需用一对括号包围,并前置反斜杠:

1 let multiplier = 3
2 let message = "\(multiplier) times 2.5 is \(Double(multiplier) * 2.5)"
3 // message is "3 times 2.5 is 7.5"
4 // message 是 "3 乘以 2.5 是 7.5"

在上例中, 常量 multiplier 的值以 \(multiplier) 的形式作为占位符插入字符串字面量中。在根据字符串插入式求出实际字符串的过程中,占位符会被 multiplier 的实际值替换。

后面一个较长的表达式用到了 multiplier 的值。该表达式计算了 Double(multiplier) * 2.5 的值,并将结果7.5)插入了字符串。上例中, \(Double(multiplier) * 2.5) 作为占位符嵌入了字符串字面量中。

注:

字符串插入中,括号里面的表达式不能包含未转义的双引号(")或反斜杠(\),也不能包含回车或换行符。

 

字符串比较

Swift 提供了三种字符串比较方法:字符串匹配,前缀匹配,后缀匹配。

 

字符串匹配

如果两个 String 值所包含的字符及其顺序完全相同,两者即相等:

1 let quotation = "We're a lot alike, you and I."
2 let sameQuotation = "We're a lot alike, you and I."
3 if quotation == sameQuotation {
4     println("These two strings are considered equal")
5 }
6 // 输出 "这两个字符串是相等的"

 

前缀/后缀匹配

检查一个字符串是否含有一个指定的字符前缀或后缀,可以使用字符串的 hasPrefixhasSuffix 方法,两种方法都接收一个 String 类型的参数并返回一个布尔值。这两种方法会拿前缀/后缀字符串与基本字符串一个字符一个字符地逐一比较。

下例有一个字符串数组,内容为莎士比亚戏剧《罗密欧与朱丽叶》(Romeo and Juliet)前两幕各场景的地点说明

 1 let romeoAndJuliet = [
 2     "Act 1 Scene 1: Verona, A public place",               //第一幕场景1:Verona,一个公共场所
 3     "Act 1 Scene 2: Capulet's mansion",                    //第一幕场景2:Capulet的家
 4     "Act 1 Scene 3: A room in Capulet's mansion",          //第一幕场景3:Capulet家的一间房内
 5     "Act 1 Scene 4: A street outside Capulet's mansion",   //第一幕场景4:Capulet家外的街上
 6     "Act 1 Scene 5: The Great Hall in Capulet's mansion",  //第一幕场景5:Capulet家的大厅内
 7     "Act 2 Scene 1: Outside Capulet's mansion",            //第二幕场景1:Capulet家外面
 8     "Act 2 Scene 2: Capulet's orchard",                    //第二幕场景2:Capulet的果园
 9     "Act 2 Scene 3: Outside Friar Lawrence's cell",        //第二幕场景3:Friar Lawrence神父的教堂外
10     "Act 2 Scene 4: A street in Verona",                   //第二幕场景4:Verona的某条街道上
11     "Act 2 Scene 5: Capulet's mansion",                    //第二幕场景5:Capulet的家
12     "Act 2 Scene 6: Friar Lawrence's cell"                 //第二幕场景6:Friar Lawrence神父的教堂
13 ]

romeoAndJuliet 数组中的元素使用 hasPrefix 方法,来统计该剧第一幕(Act 1)的场次:

1 var act1SceneCount = 0
2 for scene in romeoAndJuliet {
3     if scene.hasPrefix("Act 1 ") {
4         ++act1SceneCount
5     }
6 }
7 println("There are \(act1SceneCount) scenes in Act 1")
8 // 输出 "Act 1(第一幕) 有5场戏"

同样,用 hasSuffix 方法来统计发生在 Capulet’s mansion 和 Friar Lawrence’s cell 这些地点的场次:

 1 var mansionCount = 0
 2 var cellCount = 0
 3 for scene in romeoAndJuliet {
 4     if scene.hasSuffix("Capulet's mansion") {
 5         ++mansionCount
 6     } else if scene.hasSuffix("Friar Lawrence's cell") {
 7         ++cellCount
 8     }
 9 }
10 println("\(mansionCount) mansion scenes; \(cellCount) cell scenes")
11 // 输出 "mansion 6场; cell 2场"

 

 

谢谢,Swifter-QQ群:362232993,同好者进~ 

Fork:https://github.com/Joejo/Swift-lesson-for-chinese

 

 

 

 

 

 

 

 

 

 

 

 

 

 

版权声明:本文内容由阿里云实名注册用户自发贡献,版权归原作者所有,阿里云开发者社区不拥有其著作权,亦不承担相应法律责任。具体规则请查看《阿里云开发者社区用户服务协议》和《阿里云开发者社区知识产权保护指引》。如果您发现本社区中有涉嫌抄袭的内容,填写侵权投诉表单进行举报,一经查实,本社区将立刻删除涉嫌侵权内容。

相关文章
阿里云服务器如何登录?阿里云服务器的三种登录方法
购买阿里云ECS云服务器后如何登录?场景不同,阿里云优惠总结大概有三种登录方式: 登录到ECS云服务器控制台 在ECS云服务器控制台用户可以更改密码、更换系.
27723 0
阿里云服务器ECS登录用户名是什么?系统不同默认账号也不同
阿里云服务器Windows系统默认用户名administrator,Linux镜像服务器用户名root
15291 0
阿里云服务器端口号设置
阿里云服务器初级使用者可能面临的问题之一. 使用tomcat或者其他服务器软件设置端口号后,比如 一些不是默认的, mysql的 3306, mssql的1433,有时候打不开网页, 原因是没有在ecs安全组去设置这个端口号. 解决: 点击ecs下网络和安全下的安全组 在弹出的安全组中,如果没有就新建安全组,然后点击配置规则 最后如上图点击添加...或快速创建.   have fun!  将编程看作是一门艺术,而不单单是个技术。
19980 0
腾讯云服务器 设置ngxin + fastdfs +tomcat 开机自启动
在tomcat中新建一个可以启动的 .sh 脚本文件 /usr/local/tomcat7/bin/ export JAVA_HOME=/usr/local/java/jdk7 export PATH=$JAVA_HOME/bin/:$PATH export CLASSPATH=.
14852 0
阿里云服务器ECS远程登录用户名密码查询方法
阿里云服务器ECS远程连接登录输入用户名和密码,阿里云没有默认密码,如果购买时没设置需要先重置实例密码,Windows用户名是administrator,Linux账号是root,阿小云来详细说下阿里云服务器远程登录连接用户名和密码查询方法
22217 0
阿里云服务器怎么设置密码?怎么停机?怎么重启服务器?
如果在创建实例时没有设置密码,或者密码丢失,您可以在控制台上重新设置实例的登录密码。本文仅描述如何在 ECS 管理控制台上修改实例登录密码。
23523 0
阿里云服务器如何登录?阿里云服务器的三种登录方法
购买阿里云ECS云服务器后如何登录?场景不同,云吞铺子总结大概有三种登录方式: 登录到ECS云服务器控制台 在ECS云服务器控制台用户可以更改密码、更换系统盘、创建快照、配置安全组等操作如何登录ECS云服务器控制台? 1、先登录到阿里云ECS服务器控制台 2、点击顶部的“控制台” 3、通过左侧栏,切换到“云服务器ECS”即可,如下图所示 通过ECS控制台的远程连接来登录到云服务器 阿里云ECS云服务器自带远程连接功能,使用该功能可以登录到云服务器,简单且方便,如下图:点击“远程连接”,第一次连接会自动生成6位数字密码,输入密码即可登录到云服务器上。
36336 0
+关注
joe.huang
尚无所成,正在努力。
23
文章
0
问答
文章排行榜
最热
最新
相关电子书
更多
JS零基础入门教程(上册)
立即下载
性能优化方法论
立即下载
手把手学习日志服务SLS,云启实验室实战指南
立即下载