Foundation-String

最近写完了Swift 3.0教程 ,在接下来这段时间,继续写Foundation 的教程,帮助大家更加深入,系统的学习Foundation 框架,可能会持续一段时间,希望有兴趣的朋友加个关注!


初始化


  • 定义空字符串
 var str = String()
 var str1 = ""
  • 使用c的字符串初始化
var cString:[CChar] = [67, 97, 102, -61, -87, 0]
var str1 = String(cString: cString)
  • 使用一个字符进行初始化
var dog: Character = "🐶"
var str = String(dog)
  • 验证性初始化
var validUTF8: [CChar] = [67, 97, 102, -61, 0]
let str = String(validatingUTF8: validUTF8)
print(str)

提示:

如果里面包含一个非法的编码,初始化失败返回nil

  • 对指定的指针数据进行指定的编码
var validUTF8: [UInt8] = [67, 97, 102, 195, 0]
validUTF8.withUnsafeBufferPointer { ptr  in
    let s = String.decodeCString(ptr.baseAddress,as: UTF8.self,
                                      repairingInvalidCodeUnits: true)

输出结果:

Optional(("Caf�", true))

提示:

1.使用这个方法时一定要注意字符数组元素必须为UInt8
2.参数repairingInvalidCodeUnits 设置为true的意思,表示如果出现编码错误可以使用"\u{FFFD}" 进行替换,如果为false ,一旦出现错误的编码,则直接返回nil


常用的方法


  • 字符串是否为空
str.isEmpty
  • 是否包含前缀
var str1 = "Ku1991Zou01Ti2Ya8"
str1.hasPrefix("Ku")
  • 获取字符的个数
var str1 = "Ku1991Zou01Ti2Ya8"  
str1.characters.count // 18
  • 获取不同编码下的字节数量
 var str1 = "Ku1991Zou01Ti2Ya8我"
str1.utf8.count
str1.utf16.count
str1.unicodeScalars.count

输出结果:

20
18
18

  • 获取指定索引的字符
var str1 = "Ku1991Zou01Ti2Ya8我"
let index = str1.index(str1.startIndex, offsetBy: 8)
print(str1[index]) 

运行结果:

u

还有一个方法

str1.index(str1.startIndex, offsetBy: 30, limitedBy: str1.endIndex)

注意两者的区别:

第一个方法如果索引访问超过字符串的长度的话,系统会报错崩溃,但是第二种不会报错,会返回一个可选值nil

思考:如果索引时有条件的话,我们应该怎么做呢?看下面的例子

问题: 在一个字符串中找到第一个能被3整除的数字

let nums = "1,3,5,6,7,8,9"
let index = nums.characters.index { (char) -> Bool in
    if let num = Int(char.description){
        if num%3 == 0{
            return  true
        }
        return false
    }
    return  false
}
print(nums.characters[index!])
  • 判断字符串是不是符合ascii 编码
  let str = "werwer我"
  print(str.unicodeScalars.first?.isASCII)
  print(str.unicodeScalars.last?.isASCII)

运行结果:

true
false

  • 字符串反向输出
 let word = "Backwards"
 for char in word.characters.reversed() {
         print(char, terminator="")
  }
 // Prints "sdrawkcaB"
  • 输出对象的内容
class Student{
    var name = "大🤓"
    var age  = 23
}
let studentDescribing = String(describing: Student())
print(studentDescribing)

输出结果:

Student

提示:

显然这不是我们想要的结果,我们需要输出里面属性信息,怎么办呢? 很简单,按照下面的步骤做

//1.第一步 让对象遵守协议 CustomStringConvertible
class Student:CustomStringConvertible{
    var name = "大🤓"
    var age  = 23
     //2.第二步实现协议
    var description: String{
        return name + "\(age)"
    }
}

运行结果

大🤓23

当然我们实现了CustomStringConvertible 协议也可以使用下面的方法查看对象的描述内容

// 映射
let studentReflecting = String(reflecting: Student())
//  直接输出
print(Student())
  • 字符串的追加
var str  = "apple"
str.append("🍎") // 追加一个字符
str.append(",banana")// 追加一个字符串
str += "🍌" // 简约写法
str.append(contentsOf: ["1","2","3"])// 追加元素为字符串的数组
let newString = str.appending("new") // 追加一个字符串生成一个新的字符串

运行过程

"apple"
"apple🍎"
"apple🍎,banana"
"apple🍎,banana🍌"
"apple🍎,banana🍌123
"apple🍎,banana🍌123new

  • 大小写变换
let str = "A,B,C,D,e,f,g,h"
var lowercase = str.lowercased()
var upperCase = str.uppercased()

运行:

"A,B,C,D,e,f,g,h"
"a,b,c,d,e,f,g,h"
"A,B,C,D,E,F,G,H"

  • 遍历字符串
var  str = "🐱,🐶,🐀,🐇,🐒, 🐲,🐦,🐥"
for c in str.characters{
    print(c)
}

 for (n, c) in "Swift".characters.enumerated() {
       print("\(n): '\(c)'")
    }
   // Prints "0: 'S'"
    // Prints "1: 'w'"
    // Prints "2: 'i'"
    // Prints "3: 'f'"
    // Prints "4: 't'"
  • 将字符串进行分割
 var  str = "🐱,🐶,🐀,🐇,🐒, 🐲,🐦,🐥"
// 首先将字符串进行分割
let characters = str.characters.split { (c) -> Bool in
    c == ","
}
 // 然后进行map初始化
let array =  characters.map { (s) -> String in
    return String.init(s)
}

运行结果:

["🐱", "🐶", "🐀", "🐇", "🐒", " 🐲", "🐦", "🐥"]

由于swift强大的类型推断能力,我们一气呵成的写法如下

let array = str.characters.split(whereSeparator: { $0 == "," })
.map(String.init)
  • 截取字符串的几种方式

a.需求: 剔除掉非ascii 编码的字符

 let favemoji = "My favorite emoji is 🎉"
 if let i = favemoji.utf16.index(where: { $0 >= 128 }) {
     let asciiPrefix = String(favemoji.utf16.prefix(upTo: i))
    print(asciiPrefix)
 }

运行结果:

Optional("My favorite emoji is ")

b.需求: 从第一个位置开始截取6个字符

 let favemoji = "My favorite emoji is 🎉"
 let startIndex = favemoji.index(favemoji.startIndex, offsetBy: 1)
 let endIndex = favemoji.index(favemoji.startIndex, offsetBy: 6)
 print(favemoji[startIndex...endIndex])

c.替换字符串中指定的字符串

 var  favemoji = "My favorite emoji is 🎉"
 favemoji = favemoji.replacingOccurrences(of: "My", with: "")
print(favemoji)
  • 修改字符串中的值

需求: 找出字符串中的数字放到一个新的数组中, 并从字符串中过滤掉这些数字

var str1 = "Ku1991Zou01Ti2Ya8"
let nums = str1.withMutableCharacters { (chars) -> [Int] in
 return  chars.map({ (c) -> Int? in
        if let num = Int(c.description){
           chars.remove(at:chars.index(of: c)!)
            return num
        }
        return nil
    }).filter({$0 != nil}).map({ (num) -> Int in
        return num!
    })
}

print(str1)
print(nums)

运行结果:

KuZouTiYa
[1, 9, 9, 1, 0, 1, 2, 8]

提示:

1.首先map,将数字从当前字符串中移除,如果是数字类型则返回,不是数字的字符返回nil
2.这时候,我们的数组里面的值是可选类型,我们通过filter过滤掉nil 得到没有nil的可选值数组,此时再map一下,将可选值值编程非可选值

  • 截取字符串的写法
let favemoji = "My favorite emoji is 🎉"
     if let i = favemoji.utf16.index(where: { $0 >= 128 }) {
         let asciiPrefix = String(favemoji.utf16.prefix(upTo: i))
         print(asciiPrefix)
   }

输出:

"My favorite emoji is "

let snowy = "❄️ Let it snow! ☃️"
let nsrange = NSRange(location: 3, length: 12)
if let r = nsrange.toRange() {
let start = snowy.utf16.index(snowy.utf16.startIndex, offsetBy: r.lowerBound)
let end = snowy.utf16.index(snowy.utf16.startIndex, offsetBy: r.upperBound)
let substringRange = start..<end
print(snowy.utf16[substringRange])
}

输出:

Let it snow!


高级方法


  • 获取字符串指针地址
 var dog: [UInt8] = [97,98,99,100,0]
var str = String(cString:dog)
str.withCString { (ptr)  in
    // 获取字符串的指针地址
    print(ptr)
}

运行结果:

0x00006080000498f0

一般人不知道的东西

  • 如果你初始化时使用的"cString" 包含不合法的UTF-8 编码单元,会被系统自动替换为Unicode编码的字符"\u{FFFD}"
var str = "\u{FFFD}"
print(str)

执行结果:

"�"

var cString:[CChar] = [67,97,102,-61,0]
var str1 = String(cString: cString)

提示:

-61 就是非法的UTF-8编码,但是(-61,-87就是正确的编码),代表:é

运行结果:

"Caf�"

  • 如何获取数组的指针地址,以及如何修改指针的地址?
var validUTF8: [CChar] = [67, 97, 102, -61, -87, 0]
  validUTF8.withUnsafeBufferPointer { ptr in
    // 获取指针的地址
    print(ptr.baseAddress!)
    // 通过指针地址初始化数组
     let s = String(cString: ptr.baseAddress!)
    print(s)
    return
}

指定结果:

0x000060800004dbe0
Café

let x = validUTF8.withUnsafeMutableBufferPointer { (ptr) -> CChar in
    //获取指针的值
    print(ptr.baseAddress!.pointee)
    // 修改指针的地址,让其向后移动一位
    let s = String(cString: (ptr.baseAddress?.advanced(by: 1))!)
    print(s)
    return (ptr.baseAddress?.pointee)!
}

运行结果:

afé
67

  • 输出不同进制下的数字
var num = 10
String(num,radix:2)
String(num,radix:16,uppercase: true) //输出大写
String(num,radix:8)
String(num,radix:10)

运行:

"1010"
"A"
"12"
"10"

注意:

要求进制至少是2,至多36

  • 懒加载执行map, filter 等方法
 var str1 = "Ku"
let vowels: Set<Character> = ["a", "e", "i", "o", "u"]
var x = str1.characters.lazy.filter { a  in
   print("方法执行了")
  return  vowels.contains(a)}

print("哈哈")
print(String(x))

运行结果:

哈哈
方法执行了
方法执行了
方法执行了
方法执行了
u

🇨🇳江湖求援:

懒加载时,闭包函数会执行四次,但在普通加载的时候,只执行两次,具体原因不详,如果您知道为什么会这样,烦请留言,感激涕零😊!

  • 截取指定编码下的字符串
let hearts = "Hearts <3 ♥︎ 💘"
if let i = hearts.characters.index(of: " ") {
     // 一定要注意,这一步决定不能少
     let j = i.samePosition(in: hearts.utf8)
     // 的参数类型为 String.UTF8View.Index,所以通过上面的函数获取到对应的索引
     print(hearts.utf8.suffix(from: j))
}

运行:

<3 ♥︎ 💘

  • 输出流协议
struct ASCIILogger: TextOutputStream {
     mutating func write(_ string: String) {
         let ascii = string.unicodeScalars.lazy.map { scalar in
             scalar == "♡" || scalar == "♢"
               ? "✌️"
              : scalar.escaped(asASCII: true)
            
         }
         print(ascii.joined(separator: ""))
     }
 }
 let s = "Swift ♡ and ObjectC ♢"
 print(s)

 var asciiLogger = ASCIILogger()
 print(s, to: &asciiLogger)

运行结果:

Swift ♡ and ObjectC ♢
Swift ✌️ and ObjectC ✌️
\n

  • 比较两个字符串指定位置字符的大小
 let s1 = "They call me 'Bell'"
 let s2 = "They call me 'Stacey'"
 print(strncmp(s1, s2, 14))
 print(strncmp(s1, s2, 15))

运行结果:

0
-17

  • 检查字符是否在范围内

a.第一种

 let lowercase = "a"..."z"
 print(lowercase.contains("z"))

b.更优雅的写法

if "A"..."Z" ~= "H" {
    print("H")
}
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 160,444评论 4 365
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 67,867评论 1 298
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 110,157评论 0 248
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 44,312评论 0 214
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,673评论 3 289
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,802评论 1 223
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 32,010评论 2 315
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,743评论 0 204
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,470评论 1 246
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,696评论 2 250
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 32,187评论 1 262
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,538评论 3 258
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 33,188评论 3 240
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,127评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,902评论 0 198
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,889评论 2 283
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,741评论 2 274

推荐阅读更多精彩内容

  • 第5章 引用类型(返回首页) 本章内容 使用对象 创建并操作数组 理解基本的JavaScript类型 使用基本类型...
    大学一百阅读 3,152评论 0 4
  • __block和__weak修饰符的区别其实是挺明显的:1.__block不管是ARC还是MRC模式下都可以使用,...
    LZM轮回阅读 3,204评论 0 6
  • 昨天许下的诺言要实现,说说我的偶像刘若英。 说起喜欢刘若英,是感性的开始,是勇气的开始,而真正吸引我的是什么或许这...
    秋Irene阅读 145评论 0 0
  • 春天的风,像爱人的怀抱, 温暖、柔和。 它轻轻地抚摸着你, 给你安慰、温暖, 让你沉醉、迷恋。 夏天的风,像一位挚...
    一路向前2017阅读 196评论 2 2
  • 圭臬,读音为guī niè,是指土圭和水臬——古代测日影、正四时和测量土地的仪器,引申为某种事物的标尺、准则和法度...
    KennyP0618阅读 893评论 0 0