后台的接口因为需要兼容JS,对返回的JSON做了UrlDecode
UrlDecode嘛,很简单的啦~
只需要调用removingPercentEncoding
就可以了,于是就很高兴地开始敲代码。然而事情并没有这么简单,调用removingPercentEncoding
一直返回nil
,才发现后台返回的串它竟然是这样的:
%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...
这个是Unicode的编码格式,然而其他部分却是UTF8,这是什么鬼啊摔!为什么跟说好的不一样啊摔!还能不能愉快地敲代码了啊摔!! (╯‵□′)╯︵┻━┻
按理来说应该找后台沟通协调,告诉对方:你这里代码有问题啊!!但是理智告诉我
万一被后台妹纸打了会很没面子 —— 百里潋長
好吧,走投无路之下又没发现什么好方法可以直接转换同时有两种编码格式的字符串,所以只能自己动手,丰衣足食了
思路很简单:提取出UTF8中Unicode部分,单独进行解码再合并
- 我们使用正则查找原串中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}"//以u或U开头的四个任意字符
let regu = try? NSRegularExpression(pattern: pattern, options: NSRegularExpression.Options.caseInsensitive)
let matches = regu?.matches(in: originallyString, options: [], range: NSMakeRange(0, (originallyString as NSString).length))
看这个NSxxxx
就该知道这里正则使用的NSRegularExpression
是OC的东西,获取到的是NSRange
,而Swift3中查找需要使用Range<String.Index>
我们需要先进行NSRange
转Range<String.Index>
,再找到需要转化的Unicode串
添加一个NSRange
转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)")//这样就得到需要转换的坑爹Unicode部分了
- 将Unicode字符串转换为UTF8编码替换进原串中
这里的Unicode并不是指字符串是Unicode编码格式,而是指UTF8格式的字符串的内容是Unicode编码,有没觉得绕?反正就是不能用常规的数据解码来做就是了,不说了,小二,上代码!
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进行解码
绕了那么大一圈,我们终于去除了坑爹的Unicode部分,最后我们愉快地调用removingPercentEncoding
进行解码
let value = originallyString.removingPercentEncoding
print("\(value)")
//打印出 "{\"IsOK\": false,\"Message\": \"请传入登录类型\",\"RowCount\":0}"
这又是什么鬼啊摔!! (╯‵□′)╯︵┻━┻