`addingPercentEncoding` 在 Xcode 9 中损坏了吗?
is `addingPercentEncoding` broken in Xcode 9?
in Swift 3.x with Xcode 9 beta 2,使用 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
true
info%3Ahello%20world
我得到预期行为的案例
- Xcode 9 测试版 2,iOS 10.3.1
- Xcode 8.3.3,任意 iOS
true
info:hello%20world
是否有任何解决方法来获得 addingPercentEncoding
的有效实施,以正确遵守给定的 allowedCharacters
?
显然,当用作参考的 CharacterSet 是底层 NSCharacterSet class.
时,addingPercentEncoding
做了一些未记录的魔法
因此,要解决这个问题,您需要将 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:
let allowedCharacters = CharacterSet(bitmapRepresentation: allowedCharacters.bitmapRepresentation)
return addingPercentEncoding(withAllowedCharacters: allowedCharacters)
}
}
现在它转义 :
字符的百分比是因为 .urlPathAllowed
现在严格遵守 RFC 3986,它在第 3.3 节“路径”中说:
In addition, a URI reference (Section 4.1) may be a relative-path reference, in which case the first path segment cannot contain a colon (":") character.
因此,:
在相对路径中是允许的(这是我们在这里处理的),但在第一个组件中是不允许的。
考虑:
let string = "foo:bar/baz:qux"
print(string.addingPercentEncoding(withAllowedCharacters: .urlPathAllowed)!)
根据 RFC 3986,这将在第一个组件中对 :
进行百分比编码,但允许在后续组件中对其进行未编码:
foo%3Abar/baz:qux
这个字符集不是仅仅根据集合中的字符进行百分比编码,而是实际上应用了 RFC 3986 的相对路径逻辑。但正如 Cœur 所说,如果需要,您可以通过使用与 .urlPathAllowed
相同的允许字符构建自己的字符集来绕过此逻辑,并且该新字符集将不会应用此 RFC 3986 逻辑。
in Swift 3.x with Xcode 9 beta 2,使用 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
true
info%3Ahello%20world
我得到预期行为的案例
- Xcode 9 测试版 2,iOS 10.3.1
- Xcode 8.3.3,任意 iOS
true
info:hello%20world
是否有任何解决方法来获得 addingPercentEncoding
的有效实施,以正确遵守给定的 allowedCharacters
?
显然,当用作参考的 CharacterSet 是底层 NSCharacterSet class.
时,addingPercentEncoding
做了一些未记录的魔法
因此,要解决这个问题,您需要将 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:
let allowedCharacters = CharacterSet(bitmapRepresentation: allowedCharacters.bitmapRepresentation)
return addingPercentEncoding(withAllowedCharacters: allowedCharacters)
}
}
现在它转义 :
字符的百分比是因为 .urlPathAllowed
现在严格遵守 RFC 3986,它在第 3.3 节“路径”中说:
In addition, a URI reference (Section 4.1) may be a relative-path reference, in which case the first path segment cannot contain a colon (":") character.
因此,:
在相对路径中是允许的(这是我们在这里处理的),但在第一个组件中是不允许的。
考虑:
let string = "foo:bar/baz:qux"
print(string.addingPercentEncoding(withAllowedCharacters: .urlPathAllowed)!)
根据 RFC 3986,这将在第一个组件中对 :
进行百分比编码,但允许在后续组件中对其进行未编码:
foo%3Abar/baz:qux
这个字符集不是仅仅根据集合中的字符进行百分比编码,而是实际上应用了 RFC 3986 的相对路径逻辑。但正如 Cœur 所说,如果需要,您可以通过使用与 .urlPathAllowed
相同的允许字符构建自己的字符集来绕过此逻辑,并且该新字符集将不会应用此 RFC 3986 逻辑。