是Xcode 9中破解的“加法百分比编码”?

在使用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 beta 2,iOS 9.3
  • Xcode 9 beta 2,iOS 11.0

    真正
    资讯%3Ahello%20world

我得到预期的行为的情况

  • Xcode 9 beta 2,iOS 10.3.1
  • Xcode 8.3.3,任何iOS

    真正
    信息:你好%20world

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

显然当用作引用的CharacterSet是一个基础的NSCharacterSet类的时候,通过addingPercentEncoding做了一些未logging的魔法。

所以为了解决这个问题,你需要使你的CharacterSet成为一个纯Swift对象。 为了做到这一点,我会创build一个副本(感谢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) } } 

即使它是在.urlPathAllowed字符集中,转义字符的百分比的原因是,它似乎是严格执行RFC 3986的第3.3节,它说:在相对path中是允许的(这就是我们所说的“在这里处理),但不在第一个组件。

考虑:

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

这将符合RFC 3986的规定,在第一个组件中编码百分比,但是允许在后续组件中不编码:

FOO%3Abar /巴兹:qux

文档的方法名称和性质会导致人们得出结论:它只是根据允许的字符的百分比编码,但实际上它看起来像是在考虑它是否是.urlPathAllowed ,并应用了RFC 3986的相对path逻辑。

正如Cœur所说的,你可以通过构build自己的字符集来.urlPathAllowed ,允许使用与.urlPathAllowed相同的字符,并且不应用任何这种逻辑。