本文由CocoaChina译者星夜暮晨翻译
原文:Swift String Cheat Sheet
Swift 的字符串 API 似乎让人难以习惯。此外,每次 Swift 与其标准库版本更新的时候,字符串的 API 也时不时会发生改变。你在 Stack Overflow 上寻找到的 Swift 1.2 解决方案往往不能在 Swift 2 上按照预期(甚至完全不能)使用。虽然从好的方面来看,我发现苹果的官方文档是非常有用的(参见本文底部的链接),但是出于备查的目的以及为了帮助仍挣扎于其中的人们,在此我仍旧了列出一系列的 String 代码片段:
(Gist 和我 Github 仓库中的 Playground 都已提供)
字符串初始化
创建一个字符串对象有无数种方式可以使用,包括字面量、从其他 Swift 类型转换、Unicode等等。
varemptyString=""//空字符串 varstillEmpty=String()//另一种空字符串的形式 lethelloWorld="HelloWorld!"//字符串字面量 leta=String(true)//由布尔值转换为:"true" letb:Character="A"//显式创建一个字符类型 letc=String(b)//从字符"A"转换 letd=String(3.14)//从Double类型转换为"3.14" lete=String(1000)//从Int类型转换为"1000" letf="Result=(d)"//字符串插值"Result=3.14" letg="u{2126}"//Unicode字符,欧米伽符号Ω leth=String(count:3,repeatedValue:b)//重复字符组成的字符串"AAA"
字符串是值类型
字符串是值类型(Value Type),当用其赋值或者函数传参的时候它会被拷贝(copied)。所拷贝的值在修改的时候是懒加载的(lazy)。
varaString="Hello" varbString=aString bString+="World!"//"HelloWorld!" print("(aString)")//"Hellon"
字符串检测(空值、等值以及次序)
检测一个字符串是否为空:
emptyString.isEmpty//true
Swift 是支持 Unicode 编码的,因此相等运算符("==")将会判断 Unicode 的范式是否等价(canonical equivalence)。这意味着对于两个字符串来说,如果拥有相同的语义(linguistic meaning)和表现形式的话,即使它们由不同 Unicode 标量(scalar)组成,那么也认为这两个字符串相等:
letspain="Espa?a" lettilde="u{303}" letcountry="Espan"+"(tilde)"+"a" ifcountry==spain{ print("满足匹配!")//"满足匹配!n" }
比较次序的话:
if"aaa"<"bbb"{ print("aaa") }
前缀/后缀检测
检测一个字符串是否拥有某个前缀或者后缀:
letline="0001这里放上一些测试数据%%%%" line.hasPrefix("0001")//true line.hasSuffix("%%%%")//true
大小写互相转换
顾名思义:
letmixedCase="AbcDef" letupper=mixedCase.uppercaseString//"ABCDEF" letlower=mixedCase.lowercaseString//"abcdef"
字符集合
字符串并不是某种编码的字符集合(collection views),但是它可以通过相应的属性为不同的编码形式提供所对应的字符集合。
country.characters//characters country.unicodeScalars//Unicodescalar21-bitcodes country.utf16//UTF-16编码 country.utf8//UTF-8编码
字符总数
字符串并没有一个直接的属性用以返回其包含的字符总数,因为字符总数只对特定的编码形式来说才有意义。因此,字符总数需要通过不同编码的字符集合来访问:
//spain=Espa?a print("(spain.characters.count)")//6 print("(spain.unicodeScalars.count)")//6 print("(spain.utf16.count)")//6 print("(spain.utf8.count)")//7
使用索引来访问字符集合
每个字符集合都拥有“索引”,可以通过它来访问整个集合中的元素。这或许是在使用字符串过程中碰到的最大难点之一了。你不能使用下标语法来访问字符串中的任意元素(比如说string[5])。
要遍历某个集合中的所有元素的时候(从现在开始我都将使用 characters 集合),可以通过 for…in 循环来进行:
varsentence="Neveroddoreven" forcharacterinsentence.characters{ print(character) }
每个集合都有两个实例属性,你可以在集合中使用它们来进行索引,就如同下标语法哪样:
startIndex:返回首个元素的位置,如果为空,那么和 endIndex 的值相同。
endIndex:返回字符串逾尾(past the end)的位置。
注意到如果使用 endIndex 的话,就意味着你不能直接将其作为下标来进行使用,因为这会导致越界。
letcafe="café" cafe.startIndex//0 cafe.endIndex//4-最后一个字符之后的位置
当通过以下几种方法进行字符串修改的时候,startIndex 和 endIndex 就变得极其有用:
successor():获取下一个元素
predecessor():获取上一个元素
advancedBy(n):向前或者向后跳 n 个元素
下面是一些用例,注意到如果必要的话你可以将操作串联起来:
cafe[cafe.startIndex]//"c" cafe[cafe.startIndex.successor()]//"a" cafe[cafe.startIndex.successor().successor()]//"f" //注意到cafe[endIndex]会引发运行时错误 cafe[cafe.endIndex.predecessor()]//"é" cafe[cafe.startIndex.advancedBy(2)]//"f"
Indices 属性将返回字符串中所有元素的范围,这在遍历集合的时候很有用:
forindexincafe.characters.indices{ print(cafe[index]) }
你无法使用某个字符串中的索引来访问另一个字符串。你可以通过 distanceTo 方法将索引转换为整数值:
letword1="ABCDEF" letword2="012345" letindexC=word1.startIndex.advancedBy(2) letdistance=word1.startIndex.distanceTo(indexC)//2 letdigit=word2[word2.startIndex.advancedBy(distance)]//"2"
范围的使用
要检出字符串集合中某个范围内的元素的话,可以使用范围。范围可以通过 start 和 end 索引来完成创建:
letfqdn="useyourloaf.com" letrangeOfTLD=Range(start:fqdn.endIndex.advancedBy(-3), end:fqdn.endIndex) lettld=fqdn[rangeOfTLD]//"com"
使用 "…" 或者 "..<" 运算符可以快速完成范围的创建:
通过索引或者范围来截取字符串
要通过索引或者范围来截取字符串的话,有许多方法:
获取前缀或者后缀
如果你需要得到或者抛弃字符串前面或者后面的某些元素的话,可以:
letdigits="0123456789" lettail=String(digits.characters.dropFirst())//"123456789" letless=String(digits.characters.dropFirst(3))//"23456789" lethead=String(digits.characters.dropLast(3))//"0123456" letprefix=String(digits.characters.prefix(2))//"01" letsuffix=String(digits.characters.suffix(2))//"89" letindex4=digits.startIndex.advancedBy(4) letthru4=String(digits.characters.prefixThrough(index4))//"01234" letupTo4=String(digits.characters.prefixUpTo(index4))//"0123" letfrom4=String(digits.characters.suffixFrom(index4))//"456789"
插入或删除
要在指定位置插入字符的话,可以通过索引:
varstars="******" stars.insert("X",atIndex:stars.startIndex.advancedBy(3)) //"***X***"
要在索引出插入字符串的话,那么需要将字符串转换为字符集:
stars.insertContentsOf("YZ".characters,at:stars.endIndex.advancedBy(-3)) //"***XYZ***"
范围替换
要替换一个范围的字符串内容的话:
添加元素
可以通过“+”运算符将字符串相互连接起来,也可以使用 appendContentsOf 方法:
varmessage="Welcome" message+="Tim"//"WelcomeTim" message.appendContentsOf("!!!")//"WelcomeTim!!!
移除或者返回指定索引的元素
从一个字符串当中移除某个元素,需要注意这个方法将会使该字符串此前所有的任何索引标记(indice)失效:
vargrades="ABCDEF" letch=grades.removeAtIndex(grades.startIndex)//"A" print(grades)//"BCDEF"
范围移除
移除字符集中某个范围的字符,需要主要的是这个方法同样也会使索引标记失效:
varsequences="ABABBAABC" letmidRange=sequences.startIndex.advancedBy(4)...sequences.endIndex.advancedBy(-4) sequences.removeRange(midRange)//"ABAABC"
与 NSString 桥接
String 可以转换为 NSString 从而与 Objective-C 桥接。如果 Swift 标准库没有你所需要的功能的话,那么导入 Foundation 框架,通过 NSString 来访问这些你所需要的方法。
请注意这个桥接方法并不是无损的,因此尽可能使用 Swift 标准库完成大部分功能。
//不要忘记导入Foundation importFoundation letwelcome="helloworld!" welcome.capitalizedString//"HelloWorld!"
检索内含的字符串
使用 NSString 方法的一个例子就是执行内含字符串的检索:
lettext="123045780984" ifletrangeOfZero=text.rangeOfString("0", options:NSStringCompareOptions.BackwardsSearch){ //寻找“0”元素,然后获取之后的元素 letsuffix=String(text.characters.suffixFrom(rangeOfZero.endIndex))//"984" }
Playgournd
我发现在 Xcode 中通过 Playground 来熟悉 API 是一个非常好的选择。如果你想要抢先体验一下所有这些功能的话,这个文章的 Playground 可以从我的 Github 仓库中预告。
拓展阅读
Swift Standard Library Reference
苹果 Swift 官方博客的Strings in Swift 2
Swift Programming Language – Strings and Characters
Why is Swift’s String API So Hard?作者:Mike Ash
本文中的所有译文仅用于学习和交流目的,转载请注明文章译者、出处、和本文链接。
感谢博文视点为本期翻译活动提供赞助
I 相关 / Other
喜欢潮牌的人大概都知道Supreme 。自1994 年成立至今,短短 21 年,这个诞生于曼哈顿的品牌已成为纽约街头
当所有人还在关注 小岛秀夫和索尼将如何合作的时候,刚和他解约了的老东家科乐美 Konami 默默地在官网上贴
索尼似乎很懂得如何取悦那些老玩家。在宣布玩家可以在 PlayStation 4 上玩到 PlayStation 2 上的游戏之后,
Sues Wang 在「正在上映和即将上映」中推荐了文章,点击读一读:去看「寻龙诀」,没这些干货怎么行」王烨在
我来说一个我自己的亲身实践:如何用经济学原理选购笔记本电脑。先说一下结果:几个月前,我通过收集网上(