后臺(tái)的接口因?yàn)樾枰嫒軯S,對(duì)返回的JSON做了UrlDecode
UrlDecode嘛,很簡(jiǎn)單的啦~
只需要調(diào)用removingPercentEncoding就可以了,于是就很高興地開始敲代碼。然而事情并沒有這么簡(jiǎn)單,調(diào)用removingPercentEncoding一直返回nil,才發(fā)現(xiàn)后臺(tái)返回的串它竟然是這樣的:
%7B%22IsOK%22%3A%20false%2C%22Message%22%3A%20%22%u8BF7%u4F20%u5165%u767B%u5F55%u7C7B%u578B%22%2C%22RowCount%22%3A0%7D
看清楚,里面有部分與眾不同 ...%u8BF7%u4F20%u5165%u767B%u5F55%u7C7B%u578B... 這個(gè)是Unicode的編碼格式,然而其他部分卻是UTF8,這是什么鬼啊摔!為什么跟說(shuō)好的不一樣啊摔!還能不能愉快地敲代碼了啊摔??! (╯‵□′)╯︵┻━┻
按理來(lái)說(shuō)應(yīng)該找后臺(tái)溝通協(xié)調(diào),告訴對(duì)方:你這里代碼有問題啊?。〉抢碇歉嬖V我
萬(wàn)一被后臺(tái)妹紙打了會(huì)很沒面子 —— 百里瀲長(zhǎng)
好吧,走投無(wú)路之下又沒發(fā)現(xiàn)什么好方法可以直接轉(zhuǎn)換同時(shí)有兩種編碼格式的字符串,所以只能自己動(dòng)手,豐衣足食了
思路很簡(jiǎn)單:提取出UTF8中Unicode部分,單獨(dú)進(jìn)行解碼再合并
- 我們使用正則查找原串中Unicode格式的字符
var originallyString = "%7B%22IsOK%22%3A%20false%2C%22Message%22%3A%20%22%u8BF7%u4F20%u5165%u767B%u5F55%u7C7B%u578B%22%2C%22RowCount%22%3A0%7D"
let pattern = "%[uU].{4}"http://以u(píng)或U開頭的四個(gè)任意字符
let regu = try? NSRegularExpression(pattern: pattern, options: NSRegularExpression.Options.caseInsensitive)
let matches = regu?.matches(in: originallyString, options: [], range: NSMakeRange(0, (originallyString as NSString).length))
看這個(gè)NSxxxx就該知道這里正則使用的NSRegularExpression是OC的東西,獲取到的是NSRange,而Swift3中查找需要使用Range<String.Index>我們需要先進(jìn)行NSRange轉(zhuǎn)Range<String.Index>,再找到需要轉(zhuǎn)化的Unicode串
添加一個(gè)NSRange轉(zhuǎn)Range<String.Index>的extension方便使用
extension String {
func range(from nsRange: NSRange) -> Range<String.Index>? {
guard
let from16 = utf16.index(utf16.startIndex, offsetBy: nsRange.location, limitedBy: utf16.endIndex),
let to16 = utf16.index(from16, offsetBy: nsRange.length, limitedBy: utf16.endIndex),
let from = String.Index(from16, within: self),
let to = String.Index(to16, within: self)
else { return nil }
return from..<to
}
}
挑選出所有Unicode子串
var subs:[String] = []
for matche:NSTextCheckingResult in matches! {
let range:Range<String.Index> = originallyString.range(from: matche.range)!
subs.append(originallyString.substring(with: range))
}
print("Subs : \(subs)")//這樣就得到需要轉(zhuǎn)換的坑爹Unicode部分了
- 將Unicode字符串轉(zhuǎn)換為UTF8編碼替換進(jìn)原串中
這里的Unicode并不是指字符串是Unicode編碼格式,而是指UTF8格式的字符串的內(nèi)容是Unicode編碼,有沒覺得繞?反正就是不能用常規(guī)的數(shù)據(jù)解碼來(lái)做就是了,不說(shuō)了,小二,上代碼!
for sub in subs {
var sub1 = sub.replacingOccurrences(of: "u", with: "U").replacingOccurrences(of: "%", with: "\\")
sub1.insert("\"", at: sub1.startIndex)
sub1.insert("\"", at: sub1.endIndex)
let data = sub1.data(using: String.Encoding.utf8)
let encodeStr = try? PropertyListSerialization.propertyList(from: data!, options: PropertyListSerialization.ReadOptions.mutableContainers, format: nil) as! String
let uf8DicodeStr = encodeStr?.addingPercentEncoding(withAllowedCharacters: CharacterSet.alphanumerics)
originallyString = originallyString.replacingOccurrences(of: sub, with: uf8DicodeStr!)
print("\(originallyString)")
//得到全部由UTF8編碼組成的字符串
//%7B%22IsOK%22%3A%20false%2C%22Message%22%3A%20%22%E8%AF%B7%E4%BC%A0%E5%85%A5%E7%99%BB%E5%BD%95%E7%B1%BB%E5%9E%8B%22%2C%22RowCount%22%3A0%7D
}
- 將去除了Unicode的純UTF8格式的Decode進(jìn)行解碼
繞了那么大一圈,我們終于去除了坑爹的Unicode部分,最后我們愉快地調(diào)用removingPercentEncoding進(jìn)行解碼
let value = originallyString.removingPercentEncoding
print("\(value)")
//打印出 "{\"IsOK\": false,\"Message\": \"請(qǐng)傳入登錄類型\",\"RowCount\":0}"
這又是什么鬼啊摔!! (╯‵□′)╯︵┻━┻