首页 文章

Swift - 编码URL

提问于
浏览
220

如果我编码这样的字符串:

var escapedString = originalString.stringByAddingPercentEscapesUsingEncoding(NSUTF8StringEncoding)

它没有逃脱斜线 / .

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

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

是否有更简单的方法来编码URL,如果没有,我如何在Swift中编写它?

11 回答

  • 14

    斯威夫特3:

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

    1. encodingQuery:

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

    result:

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

    result:

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

    斯威夫特4:

    它取决于您的服务器遵循的编码规则 .

    Apple提供此类方法,但它没有报告它遵循的RCF协议 .

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

    在这个有用的tool之后,你应该保证为你的参数编码这些字符:

    • $(美元符号)变为%24

    • &(&符号)变为%26

    • (加号)成为%2B

    • ,(逗号)变为%2C

    • :(冒号)变为%3A

    • ; (半结肠)变为%3B

    • =(等于)变为%3D

    • ? (问号)变为%3F

    • @(商业A / At)成为%40

    换句话说,关于URL编码,您应该遵循RFC 1738 protocol .

    And Swift don't cover the encoding of the + char for example ,但它适用于这三个 @ : ? 字符 .

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

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

    希望这可以帮助那些疯狂的人搜索这些信息 .

  • 32

    我自己需要这个,所以我编写了一个String扩展,它允许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
        }
    }
    

    请享用!

  • 482

    斯威夫特4

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

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

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

    Note 通过使用 .alphanumerics ,它将编码一些不需要编码的字符(如 -._~ - 参见2.3.RFC 3986中未保留的字符) . 我发现使用 .alphanumerics 比构造自定义字符集更简单,并且不介意要编码一些其他字符 . 如果这让您感到困扰,请构建一个自定义字符集,如How to percent encode a URL String中所述,例如:

    var allowed = CharacterSet.alphanumerics
    allowed.insert(charactersIn: "-._~") // as per RFC 3986
    let encoded = parameter.addingPercentEncoding(withAllowedCharacters: allowed)
    let url = "http://www.example.com/?name=\(encoded!)"
    

    Warning: encoded 参数强制解包 . 对于无效的unicode字符串,它可能会崩溃 . 见Why is the return value of String.addingPercentEncoding() optional? . 而不是强行展开 encoded! ,您可以使用 encoded ?? "" 或使用 if let encoded = ... .

  • 8

    斯威夫特3

    在Swift 3中有 addingPercentEncoding

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

    输出:

    测试%2Ftest

    斯威夫特1

    在iOS 7及更高版本中有 stringByAddingPercentEncodingWithAllowedCharacters

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

    输出:

    测试%2Ftest

    以下是有用(反向)字符集:

    URLFragmentAllowedCharacterSet  "#%<>[\]^`{|}
    URLHostAllowedCharacterSet      "#%/<>?@\^`{|}
    URLPasswordAllowedCharacterSet  "#%/:<>?@[\]^`{|}
    URLPathAllowedCharacterSet      "#%;<>?[\]^`{|}
    URLQueryAllowedCharacterSet     "#%<>[\]^`{|}
    URLUserAllowedCharacterSet      "#%/:<>?@[\]^`
    

    如果要转义不同的字符集,请创建一个集合:
    添加"="字符的示例:

    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)\'")
    }
    
  • 2

    这个适合我 .

    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/ .

  • 36

    一切都是一样的

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

    斯威夫特3:

    let allowedCharacterSet = (CharacterSet(charactersIn: "!*'();:@&=+$,/?%#[] ").inverted)
    
    if let escapedString = originalString.addingPercentEncoding(withAllowedCharacters: allowedCharacterSet) {
    //do something with escaped string
    }
    
  • 20

    Swift 4 (not tested - please comment if it works or not. Thanks @sumizome for suggestion)

    var allowedQueryParamAndKey = NSCharacterSet.urlQueryAllowed
    allowedQueryParamAndKey.remove(charactersIn: ";/?:@&=+$, ")
    paramOrKey.addingPercentEncoding(withAllowedCharacters: allowedQueryParamAndKey)
    

    Swift 3

    let allowedQueryParamAndKey =  NSCharacterSet.urlQueryAllowed.remove(charactersIn: ";/?:@&=+$, ")
    paramOrKey.addingPercentEncoding(withAllowedCharacters: allowedQueryParamAndKey)
    

    Swift 2.2 (从Zaph借用并更正url查询键和参数值)

    var allowedQueryParamAndKey =  NSCharacterSet(charactersInString: ";/?:@&=+$, ").invertedSet
    paramOrKey.stringByAddingPercentEncodingWithAllowedCharacters(allowedQueryParamAndKey)
    

    Example:

    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"
    

    这是一个较短版本的Bryan Chen 's answer. I' d猜测 urlQueryAllowed 允许控制字符通过哪个很好,除非它们构成查询字符串中的键或值的一部分,此时它们需要被转义 .

  • 9

    这在Swift 4.2中对我有用 . 用例是从剪贴板或类似的URL获取一个URL,该URL可能已经有转义字符,但也包含可能导致 URL(string:) 失败的Unicode字符 .

    func encodedUrl(from string: String) -> URL? {
        // Remove preexisting encoding
        guard let decodedString = string.removingPercentEncoding,
            // Reencode, to revert decoding while encoding missed characters
            let percentEncodedString = decodedString.addingPercentEncoding(withAllowedCharacters: .urlQueryAllowed) else {
                // Coding failed
                return nil
        }
        // Create URL from encoded string, or nil if failed
        return URL(string: percentEncodedString)
    }
    
    let urlText = "https://www.example.com/폴더/search?q=123&foo=bar&multi=eggs+and+ham&hangul=한글&spaced=lovely%20spam&illegal=<>"
    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

    请注意,保留 %20+ 间距,对Unicode字符进行编码,并且原始 urlText 中的 %20 不进行双重编码 .

    Caveat: 这是一个快捷方式,因为它在整个URL上使用 .urlQueryAllowed ;它还假设URL已在浏览器中运行 . 明智地使用!我也愿意接受建议(我没有用 URLComponents 斩断整个网址,应用单个字符集,并重新组装) .

  • 11

    您可以使用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, host: String, path: String, queryItems: [URLQueryItem]) {
            self.init()
            self.scheme = scheme
            self.host = host
            self.path = path
            self.queryItems = queryItems
        }
    }
    
    if let url = URLComponents(scheme: "https",
                                 host: "www.google.com",
                                 path: "/search",
                           queryItems: [URLQueryItem(name: "q", value: "Formula One")]).url {
    
        print(url)  // https://www.google.com/search?q=Formula%20One
    }
    

相关问题