如果我像这样编码一个字符串:
var escapedString = originalString.stringByAddingPercentEscapesUsingEncoding(NSUTF8StringEncoding)
它没有逃脱斜杠/。
我搜索并找到了这段Objective C代码:
NSString *encodedString = (NSString *)CFURLCreateStringByAddingPercentEscapes(
NULL,
(CFStringRef)unencodedString,
NULL,
(CFStringRef)@"!*'();:@&=+$,/?%#[]",
kCFStringEncodingUTF8 );
是否有一个更简单的方法来编码一个URL,如果没有,我怎么写在Swift?
斯威夫特4:
这取决于您的服务器所遵循的编码规则。
苹果提供了这个类方法,但它没有报告它遵循哪种RCF协议。
var escapedString = originalString.addingPercentEncoding(withAllowedCharacters: .urlHostAllowed)!
使用这个有用的工具,你应该保证这些字符的编码为你的参数:
$(美元符号)变为%24
&(&)变成%26
+(+)变成%2B
,(逗号)变成%2C
:(冒号)变成%3A
; (分号)变成%3B
=(等于)变成%3D
? (问号)变成%3F
@(商业A / At)变成%40
换句话说,谈到URL编码,您应该遵循RFC 1738协议。
Swift不包括+字符的编码,但它可以很好地使用这三个@:?识字课。
因此,要正确编码每个参数,.urlHostAllowed选项是不够的,你还应该添加特殊字符,例如:
encodedParameter = parameter.replacingOccurrences(of: "+", with: "%2B")
希望这能帮助那些变得疯狂的人搜索这些信息。
Swift 4和5(谢谢@sumizome的建议。感谢@FD_和@derickito的测试)
var allowedQueryParamAndKey = NSCharacterSet.urlQueryAllowed
allowedQueryParamAndKey.remove(charactersIn: ";/?:@&=+$, ")
paramOrKey.addingPercentEncoding(withAllowedCharacters: allowedQueryParamAndKey)
斯威夫特3
let allowedQueryParamAndKey = NSCharacterSet.urlQueryAllowed.remove(charactersIn: ";/?:@&=+$, ")
paramOrKey.addingPercentEncoding(withAllowedCharacters: allowedQueryParamAndKey)
Swift 2.2(借用Zaph's,修正url查询键和参数值)
var allowedQueryParamAndKey = NSCharacterSet(charactersInString: ";/?:@&=+$, ").invertedSet
paramOrKey.stringByAddingPercentEncodingWithAllowedCharacters(allowedQueryParamAndKey)
例子:
let paramOrKey = "https://some.website.com/path/to/page.srf?a=1&b=2#top"
paramOrKey.addingPercentEncoding(withAllowedCharacters: allowedQueryParamAndKey)
// produces:
"https%3A%2F%2Fsome.website.com%2Fpath%2Fto%2Fpage.srf%3Fa%3D1%26b%3D2%23top"
以下是陈布莱恩回答的一个简短版本。我猜urlQueryAllowed允许控制字符通过,这很好,除非它们在查询字符串中形成键或值的一部分,在这一点上它们需要转义。
斯威夫特3
在Swift 3中增加了percentencoding
let originalString = "test/test"
let escapedString = originalString.addingPercentEncoding(withAllowedCharacters: .urlHostAllowed)
print(escapedString!)
输出:
测试%2F测试
斯威夫特1
在ios7及以上版本中,有stringByAddingPercentEncodingWithAllowedCharacters
var originalString = "test/test"
var escapedString = originalString.stringByAddingPercentEncodingWithAllowedCharacters(.URLHostAllowedCharacterSet())
println("escapedString: \(escapedString)")
输出:
测试%2F测试
以下是有用的(倒置的)字符集:
URLFragmentAllowedCharacterSet "#%<>[\]^`{|}
URLHostAllowedCharacterSet "#%/<>?@\^`{|}
URLPasswordAllowedCharacterSet "#%/:<>?@[\]^`{|}
URLPathAllowedCharacterSet "#%;<>?[\]^`{|}
URLQueryAllowedCharacterSet "#%<>[\]^`{|}
URLUserAllowedCharacterSet "#%/:<>?@[\]^`
如果你想要转义一组不同的字符,创建一个set:
添加“=”字符的示例:
var originalString = "test/test=42"
var customAllowedSet = NSCharacterSet(charactersInString:"=\"#%/<>?@\\^`{|}").invertedSet
var escapedString = originalString.stringByAddingPercentEncodingWithAllowedCharacters(customAllowedSet)
println("escapedString: \(escapedString)")
输出:
测试% 2Ftest % 3D42
使用实例验证集合中不存在的ascii字符。
func printCharactersInSet(set: NSCharacterSet) {
var characters = ""
let iSet = set.invertedSet
for i: UInt32 in 32..<127 {
let c = Character(UnicodeScalar(i))
if iSet.longCharacterIsMember(i) {
characters = characters + String(c)
}
}
print("characters not in set: \'\(characters)\'")
}
Swift 4 & 5
要在URL中编码参数,我发现使用. alphanumics字符集是最简单的选择:
let urlEncoded = value.addingPercentEncoding(withAllowedCharacters: .alphanumerics)
let url = "http://www.example.com/?name=\(urlEncoded!)"
使用URL编码的任何标准字符集(如. urlqueryallowed或. urlhostallowed)都不起作用,因为它们不排除=或&字符。
注意,通过使用. alphannumeric,它将编码一些不需要编码的字符(如-,.,_或~ -参见2.3。RFC 3986中的非保留字符)。我发现使用. alphanumics比构造一个自定义字符集更简单,并且不介意编码一些额外的字符。如果这困扰你,构造一个自定义字符集,如描述如何百分比编码URL字符串,例如:
// Store allowed character set for reuse (computed lazily).
private let urlAllowed: CharacterSet =
.alphanumerics.union(.init(charactersIn: "-._~")) // as per RFC 3986
extension String {
var urlEncoded: String? {
return addingPercentEncoding(withAllowedCharacters: urlAllowed)
}
}
let url = "http://www.example.com/?name=\(value.urlEncoded!)"
警告:urlEncoded参数是强制打开的。对于无效的unicode字符串,它可能会崩溃。参见为什么String.addingPercentEncoding()的返回值是可选的?而不是强制展开urlEncoded!你可以使用urlEncoded ??或者if let urlEncoded = urlEncoded{…}。