8

在带有 Xcode 9 beta 2 的 Swift 3.x 中,使用addingPercentEncoding会产生意想不到的结果。CharacterSet.urlPathAllowed总是包含“:”,所以根据 的定义addingPercentEncoding,它永远不应该逃避它。然而,使用这段代码:

// always true
print(CharacterSet.urlPathAllowed.contains(":"))
let myString = "info:hello world"
let escapedString = myString.addingPercentEncoding(withAllowedCharacters: .urlPathAllowed)!
print(escapedString)

我得到这些结果:

我得到不良行为的情况

  • Xcode 9 测试版 2,iOS 9.3
  • Xcode 9 测试版 2,iOS 11.0

    真实
    信息%3Ahello%20world

我得到预期行为的情况

  • Xcode 9 测试版 2,iOS 10.3.1
  • Xcode 8.3.3,任何 iOS

    真实
    信息:你好%20world

是否有任何解决方法来获得addingPercentEncoding正确尊重给定的工作实现allowedCharacters

4

2 回答 2

11

显然,addingPercentEncoding当用作参考的 CharacterSet 是基础 NSCharacterSet 类时,会发生一些未记录的魔法。

所以要解决这个问题,你需要让你的 CharacterSet 成为一个纯 Swift 对象。为此,我将创建一个副本(感谢 Martin R!),这样邪恶的魔法就消失了:

let myString = "info:hello world"
let csCopy = CharacterSet(bitmapRepresentation: CharacterSet.urlPathAllowed.bitmapRepresentation)
let escapedString = myString.addingPercentEncoding(withAllowedCharacters: csCopy)!
//always "info:hello%20world"
print(escapedString)

作为扩展:

extension String {
    func safeAddingPercentEncoding(withAllowedCharacters allowedCharacters: CharacterSet) -> String? {
        // using a copy to workaround magic: https://stackoverflow.com/q/44754996/1033581
        let allowedCharacters = CharacterSet(bitmapRepresentation: allowedCharacters.bitmapRepresentation)
        return addingPercentEncoding(withAllowedCharacters: allowedCharacters)
    }
}
于 2017-06-26T08:13:57.783 回答
9

它现在百分比转义:字符的原因是.urlPathAllowed现在严格遵守RFC 3986,它在第 3.3 节“路径”中说:

此外,URI 引用(第 4.1 节)可能是相对路径引用,在这种情况下,第一个路径段不能包含冒号(“:”)字符。

因此,:在相对路径中是允许的(这是我们在这里处理的),但在第一个组件中是不允许的。

考虑:

let string = "foo:bar/baz:qux"
print(string.addingPercentEncoding(withAllowedCharacters: .urlPathAllowed)!)

这将按照 RFC 3986 对:第一个组件进行百分比编码,但允许在后续组件中未编码:

foo%3Abar/baz:qux

此字符集不是仅根据字符集中的字符进行百分比编码,而是实际上应用了 RFC 3986 的相对路径逻辑。但正如 Cœur 所说,如果需要,您可以通过使用与 相同的允许字符构建自己的字符集来绕过此逻辑.urlPathAllowed,并且该新字符集不会应用此 RFC 3986 逻辑。

于 2017-06-26T08:35:19.907 回答