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

var escapedString = originalString.stringByAddingPercentEscapesUsingEncoding(NSUTF8StringEncoding)

它没有逃脱斜杠/。

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

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

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


当前回答

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{…}。

其他回答

我自己也需要这个,所以我写了一个字符串扩展,既允许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
    }
}

享受吧!

斯威夫特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. 编码网址:

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"

这在Swift 5中为我工作。用例是从剪贴板或类似的地方获取URL,该URL可能已经有转义字符,但还包含Unicode字符,这可能导致URLComponents或URL(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没有被双重编码,锚(片段或#)仍然保留。

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

斯威夫特5 你可以尝试.afURLQueryAllowed选项,如果你想编码字符串如下

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

//编码后的字符串将像en6hAD9%2FRjY%2BSnGm%26B

一切都是一样的

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

// test%2Ftest