Swift编码URL

如果我像这样编码一个字符串:

var escapedString = originalString.stringByAddingPercentEscapesUsingEncoding(NSUTF8StringEncoding)

它不会转义斜杠/

我搜索并找到了这段Objective C代码:

NSString *encodedString = (NSString *)CFURLCreateStringByAddingPercentEscapes(
NULL,
(CFStringRef)unencodedString,
NULL,
(CFStringRef)@"!*'();:@&=+$,/?%#[]",
kCFStringEncodingUTF8 );

是否有一个更简单的方法来编码一个URL,如果没有,我怎么写在Swift?

328467 次浏览

斯威夫特3

在Swift 3中有addingPercentEncoding

let originalString = "test/test"
let escapedString = originalString.addingPercentEncoding(withAllowedCharacters: .urlHostAllowed)
print(escapedString!)

输出:

测试% 2英尺

斯威夫特1

在ios7及以上版本中有stringByAddingPercentEncodingWithAllowedCharacters

var originalString = "test/test"
var escapedString = originalString.stringByAddingPercentEncodingWithAllowedCharacters(.URLHostAllowedCharacterSet())
println("escapedString: \(escapedString)")

输出:

测试% 2英尺

以下是有用的(倒置的)字符集:

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)")

输出:

测试% 2英尺% 3 d42

使用实例验证集合中不存在的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)\'")
}

一切都是一样的

var str = CFURLCreateStringByAddingPercentEscapes(
nil,
"test/test",
nil,
"!*'();:@&=+$,/?%#[]",
CFStringBuiltInEncodings.UTF8.rawValue
)


// test%2Ftest

我自己也需要这个,所以我写了一个字符串扩展,既允许URLEncoding字符串,以及更常见的最终目标,将参数字典转换为“GET”风格的URL参数:

extension String {
func URLEncodedString() -> String? {
var escapedString = self.addingPercentEncoding(withAllowedCharacters: .urlHostAllowed)
return escapedString
}
static func queryStringFromParameters(parameters: Dictionary<String,String>) -> String? {
if (parameters.count == 0)
{
return nil
}
var queryString : String? = nil
for (key, value) in parameters {
if let encodedKey = key.URLEncodedString() {
if let encodedValue = value.URLEncodedString() {
if queryString == nil
{
queryString = "?"
}
else
{
queryString! += "&"
}
queryString! += encodedKey + "=" + encodedValue
}
}
}
return queryString
}
}

享受吧!

这个对我有用。

func stringByAddingPercentEncodingForFormData(plusForSpace: Bool=false) -> String? {


let unreserved = "*-._"
let allowed = NSMutableCharacterSet.alphanumericCharacterSet()
allowed.addCharactersInString(unreserved)


if plusForSpace {
allowed.addCharactersInString(" ")
}


var encoded = stringByAddingPercentEncodingWithAllowedCharacters(allowed)


if plusForSpace {
encoded = encoded?.stringByReplacingOccurrencesOfString(" ", withString: "+")
}
return encoded
}

我从这个链接找到了上面的函数:http://useyourloaf.com/blog/how-to-percent-encode-a-url-string/

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)

斯威夫特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允许控制字符通过,除非它们在你的查询字符串中形成键或值的一部分,在这一点上它们需要转义。

斯威夫特5:

extension String {
var urlEncoded: String? {
let allowedCharacterSet = CharacterSet.alphanumerics.union(CharacterSet(charactersIn: "~-_."))
return self.addingPercentEncoding(withAllowedCharacters: allowedCharacterSet)
}
}


print("\u{48}ello\u{9}world\u{7}\u{0}".urlEncoded!) // prints Hello%09world%07%00
print("The string ü@foo-bar".urlEncoded!) // prints The%20string%20%C3%BC%40foo-bar




你可以使用URLComponents来避免手动对查询字符串进行百分比编码:

let scheme = "https"
let host = "www.google.com"
let path = "/search"
let queryItem = URLQueryItem(name: "q", value: "Formula One")




var urlComponents = URLComponents()
urlComponents.scheme = scheme
urlComponents.host = host
urlComponents.path = path
urlComponents.queryItems = [queryItem]


if let url = urlComponents.url {
print(url)   // "https://www.google.com/search?q=Formula%20One"
}

extension URLComponents {
init(scheme: String = "https",
host: String = "www.google.com",
path: String = "/search",
queryItems: [URLQueryItem]) {
self.init()
self.scheme = scheme
self.host = host
self.path = path
self.queryItems = queryItems
}
}

let query = "Formula One"
if let url = URLComponents(queryItems: [URLQueryItem(name: "q", value: query)]).url {
print(url)  // https://www.google.com/search?q=Formula%20One
}

斯威夫特3:

let originalString = "http://www.ihtc.cc?name=htc&title=iOS开发工程师"

1. encodingQuery:

let escapedString = originalString.addingPercentEncoding(withAllowedCharacters:NSCharacterSet.urlQueryAllowed)

结果:

"http://www.ihtc.cc?name=htc&title=iOS%E5%BC%80%E5%8F%91%E5%B7%A5%E7%A8%8B%E5%B8%88"

2. encodingURL:

let escapedString = originalString.addingPercentEncoding(withAllowedCharacters: .urlHostAllowed)

结果:

"http:%2F%2Fwww.ihtc.cc%3Fname=htc&title=iOS%E5%BC%80%E5%8F%91%E5%B7%A5%E7%A8%8B%E5%B8%88"

斯威夫特4:

这取决于您的服务器所遵循的编码规则。

苹果提供了这个类方法,但它没有报告它遵循哪种RCF协议。

var escapedString = originalString.addingPercentEncoding(withAllowedCharacters: .urlHostAllowed)!

遵循这个有用的工具,你应该保证这些字符为你的参数编码:

  • $(美元符号)变为%24
  • ,(&号)变成%26
  • +(+)变成%2B
  • ,(逗号)变成%2C
  • :(冒号)变成%3A
  • ; (分号)变成%3B
  • =(等于)变成%3D
  • ? (问号)变成%3F
  • @(商业A / At)变成%40

换句话说,谈到URL编码,你应该遵循rfc1738协议

Swift不包括+字符的编码,但它与这三个@ ?字符一起工作得很好。

因此,要正确编码每个参数,.urlHostAllowed选项是不够的,你还应该添加特殊字符,例如:

encodedParameter = parameter.replacingOccurrences(of: "+", with: "%2B")

希望这能帮助那些变得疯狂的人搜索这些信息。

Swift 4 &5

要在URL中编码参数,我发现使用.alphanumerics字符集是最简单的选择:

let urlEncoded = value.addingPercentEncoding(withAllowedCharacters: .alphanumerics)
let url = "http://www.example.com/?name=\(urlEncoded!)"

使用任何用于URL编码的标准字符集(如.urlQueryAllowed.urlHostAllowed)都不起作用,因为它们不排除=&字符。

请注意,通过使用.alphanumerics,它将编码一些不需要编码的字符(如-._~——参见RFC 3986中的2.3. 无限制的字符)。我发现使用.alphanumerics比构造一个自定义字符集更简单,并且不介意编码一些额外的字符。如果这让你感到困扰,可以构造一个如何百分比编码一个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 ?? ""if let urlEncoded = urlEncoded { ... }来代替强制展开urlEncoded!

这在斯威夫特5中为我工作。用例是从剪贴板或类似的地方获取URL,该URL可能已经有转义字符,但还包含Unicode字符,这可能导致URLComponentsURL(string:)失败。

首先,创建一个包含所有url合法字符的字符集:

extension CharacterSet {


/// Characters valid in at least one part of a URL.
///
/// These characters are not allowed in ALL parts of a URL; each part has different requirements. This set is useful for checking for Unicode characters that need to be percent encoded before performing a validity check on individual URL components.
static var urlAllowedCharacters: CharacterSet {
// Start by including hash, which isn't in any set
var characters = CharacterSet(charactersIn: "#")
// All URL-legal characters
characters.formUnion(.urlUserAllowed)
characters.formUnion(.urlPasswordAllowed)
characters.formUnion(.urlHostAllowed)
characters.formUnion(.urlPathAllowed)
characters.formUnion(.urlQueryAllowed)
characters.formUnion(.urlFragmentAllowed)


return characters
}
}

接下来,用一个方法扩展String来编码url:

extension String {


/// Converts a string to a percent-encoded URL, including Unicode characters.
///
/// - Returns: An encoded URL if all steps succeed, otherwise nil.
func encodedUrl() -> URL? {
// Remove preexisting encoding,
guard let decodedString = self.removingPercentEncoding,
// encode any Unicode characters so URLComponents doesn't choke,
let unicodeEncodedString = decodedString.addingPercentEncoding(withAllowedCharacters: .urlAllowedCharacters),
// break into components to use proper encoding for each part,
let components = URLComponents(string: unicodeEncodedString),
// and reencode, to revert decoding while encoding missed characters.
let percentEncodedUrl = components.url else {
// Encoding failed
return nil
}


return percentEncodedUrl
}


}

可以这样测试:

let urlText = "https://www.example.com/폴더/search?q=123&foo=bar&multi=eggs+and+ham&hangul=한글&spaced=lovely%20spam&illegal=<>#top"
let url = encodedUrl(from: urlText)

url在结尾的值:https://www.example.com/%ED%8F%B4%EB%8D%94/search?q=123&foo=bar&multi=eggs+and+ham&hangul=%ED%95%9C%EA%B8%80&spaced=lovely%20spam&illegal=%3C%3E#top

注意,%20+空格都被保留,Unicode字符被编码,原始urlText中的%20没有被双重编码,锚(片段或#)保留。

现在检查每个组件的有效性。

斯威夫特4.2

有时发生这种情况只是因为在段码中有空间或没有URL编码的参数通过API URL。

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

注意:不要忘记探索bitmapRepresentation

斯威夫特4.2

一个快速的解决方案。将originalString替换为要编码的字符串。

var encodedString = originalString.addingPercentEncoding(withAllowedCharacters: CharacterSet(charactersIn: "!*'();:@&=+$,/?%#[]{} ").inverted)

< a href = " https://repl。它/ repl DentalWarmTechnician noreferrer“rel = >在线操场演示< / >

let Url = URL(string: urlString.addingPercentEncoding(withAllowedCharacters: .urlQueryAllowed) ?? "")

对于Swift 5到endcode字符串

func escape(string: String) -> String {
let allowedCharacters = string.addingPercentEncoding(withAllowedCharacters: CharacterSet(charactersIn: ":=\"#%/<>?@\\^`{|}").inverted) ?? ""
return allowedCharacters
}

如何使用?

let strEncoded = self.escape(string: "http://www.edamam.com/ontologies/edamam.owl#recipe_e2a1b9bf2d996cbd9875b80612ed9aa4")
print("escapedString: \(strEncoded)")

这些答案对我都没用。当url包含非英语字符时,我们的应用程序崩溃了。

 let unreserved = "-._~/?%$!:"
let allowed = NSMutableCharacterSet.alphanumeric()
allowed.addCharacters(in: unreserved)


let escapedString = urlString.addingPercentEncoding(withAllowedCharacters: allowed as CharacterSet)

根据您要做的事情的参数,您可能只想创建自己的字符集。上面的语句允许使用英文字符,而-._~/?%$!:

帮助我的是,我创建了一个单独的NSCharacterSet,并将它用于UTF-8编码的字符串,即textToEncode,以生成所需的结果:

var queryCharSet = NSCharacterSet.urlQueryAllowed
queryCharSet.remove(charactersIn: "+&?,:;@+=$*()")
    

let utfedCharacterSet = String(utf8String: textToEncode.cString(using: .utf8)!)!
let encodedStr = utfedCharacterSet.addingPercentEncoding(withAllowedCharacters: queryCharSet)!
    

let paramUrl = "https://api.abc.eu/api/search?device=true&query=\(escapedStr)"

< >强劲迅速5 你可以尝试.afURLQueryAllowed选项,如果你想编码字符串如下

let testString = "6hAD9/RjY+SnGm&B"
let escodedString = testString.addingPercentEncoding(withAllowedCharacters: .afURLQueryAllowed)
print(escodedString!)

//编码后的字符串将类似en6hAD9 % 2 frjy % 2 bsngm % 26 b

版本:斯威夫特5

// space convert to +
let mstring = string.replacingOccurrences(of: " ", with: "+")
// remove special character
var allowedQueryParamAndKey = NSCharacterSet.urlQueryAllowed
allowedQueryParamAndKey.remove(charactersIn: "!*'\"();:@&=+$,/?%#[]%")
return mstring.addingPercentEncoding(withAllowedCharacters: allowedQueryParamAndKey) ?? mstring