【问题标题】:Swift URL.path changes encoding of utf-8 charactersSwift URL.path 更改 utf-8 字符的编码
【发布时间】:2018-10-31 23:07:55
【问题描述】:

为什么在 Swift 4.2 中将 String 转换为 URL,然后使用 url.pathURL 转换回 String 会更改特殊字符的编码,例如德语变音符号(ä、ö、ü ),即使我使用 utf-8 编码?

我写了一些示例代码来说明我的问题。我将字符串编码为 base64 以表明存在差异。

我也有类似的未解决的特殊字符问题和 swift 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 不同。

"L3BhdGgvdG8vZmlsZQ==" for base64

"L3BhdGgvdG8vZmlsZQ==" for base64Url

"L3BhdGgvdG8vZmlsZS93aXRoL3VtbGF1dHMvdGVzdMOkw7bDvA==" for base64Umlauts

"L3BhdGgvdG8vZmlsZS93aXRoL3VtbGF1dHMvdGVzdGHMiG/MiHXMiA==" for base64UrlUmlauts

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

【问题讨论】:

    标签: ios swift macos encoding utf-8


    【解决方案1】:

    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编码有什么不同呢?

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

    let urlStr = urlUmlauts.path.precomposedStringWithCanonicalMapping
    

    现在您从以下地址获得true

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

    【讨论】:

    • 谢谢,现在可以了!但是当我将这个String 作为参数传递给Process 时,NSTask 似乎在后台将其转换为错误的编码(参见here)。请问我该如何解决那里的问题?
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-06-09
    • 2017-07-27
    • 2011-06-17
    • 2018-07-02
    相关资源
    最近更新 更多