Swift URL.path更改utf-8字符的编码

时间:2018-10-31 23:07:55

标签: ios swift macos encoding utf-8

为什么在Swift 4.2中将String转换为URL,然后使用URLString转换回url.path会改变特殊编码即使我使用utf-8编码,还是像德国变音符号(ä,ö,ü)这样的字符?

我写了一些示例代码来展示我的问题。我将字符串编码为base64,以显示它们之间的区别。

我也遇到类似的未解决问题,即特殊字符和快捷的here

示例代码

let string = "/path/to/file"
let stringUmlauts = "/path/to/file/with/umlauts/testäöü"

let base64 = Data(string.utf8).base64EncodedString()
let base64Umlauts = Data(stringUmlauts.utf8).base64EncodedString()

print(base64, base64Umlauts)

let url = URL(fileURLWithPath: string)
let urlUmlauts = URL(fileURLWithPath: stringUmlauts)

let base64Url = Data(url.path.utf8).base64EncodedString()
let base64UrlUmlauts = Data(urlUmlauts.path.utf8).base64EncodedString()

print(base64Url, base64UrlUmlauts)

输出

base64base64Url字符串保持不变,但base64Umlautsbase64UrlUmlauts不同。

  

base64的“ L3BhdGgvdG8vZmlsZQ ==”

     

base64Url的“ L3BhdGgvdG8vZmlsZQ ==”

     

base64Umlauts的” L3BhdGgvdG8vZmlsZS93aXRoL3VtbGF1dHMvdGVzdMOkw7bDvA ==“      

base64UrlUmlauts的L3BhdGgvdG8vZmlsZS93aXRoL3VtbGF1dHMvdGVzdGHMiG / MiHXMiA ==“

当我将base64Umlautsbase64UrlUmlauts字符串放入在线Base64解码器中时,它们都显示/path/to/file/with/umlauts/testäöü,但是ä, ö, ü是不同的(不是视觉上的)。

1 个答案:

答案 0 :(得分:3)

stringUmlauts.utf8使用Unicode字符äöü

但是urlUmlauts.path.utf8使用Unicode字符aou,每个后跟组合的¨

这就是为什么您获得不同的base64编码的原因-字符看起来相同,但实际上编码不同。

真正有趣的是Array(stringUmlauts)Array(urlUmlauts.path)是相同的。直到对其他完全相同的String值执行UTF-8编码后,差异才会出现。

由于base64编码无关紧要,因此这里的测试更为简洁:

let stringUmlauts = "/path/to/file/with/umlauts/testäöü"
let urlUmlauts = URL(fileURLWithPath: stringUmlauts)

print(stringUmlauts, urlUmlauts.path) // Show the same

let rawStr = stringUmlauts
let urlStr = urlUmlauts.path

print(rawStr == urlStr) // true
print(Array(rawStr) == Array(urlStr)) // true
print(Array(rawStr.utf8) == Array(urlStr.utf8)) // false!!!

那么两个相等的字符串的UTF-8编码有何不同?

一种解决方案是在precomposedStringWithCanonicalMapping的结果上使用path

let urlStr = urlUmlauts.path.precomposedStringWithCanonicalMapping

现在,您从true中获得

print(Array(rawStr.utf8) == Array(urlStr.utf8)) // now true