Swift - encode URL

后端 未结 17 1888
無奈伤痛
無奈伤痛 2020-11-21 22:20

If I encode a string like this:

var escapedString = originalString.stringByAddingPercentEscapesUsingEncoding(NSUTF8StringEncoding)

it does

相关标签:
17条回答
  • 2020-11-21 22:49

    SWIFT 4.2

    Sometimes this happened just because there is space in slug OR absence of URL encoding for parameters passing through 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)
    

    NOTE : Don't forget to explore about bitmapRepresentation.

    0 讨论(0)
  • 2020-11-21 22:52

    Swift 4 & 5

    To encode a parameter in URL I find using .alphanumerics character set the easiest option:

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

    Using any of the standard Character Sets for URL Encoding (like URLQueryAllowedCharacterSet or URLHostAllowedCharacterSet) won't work, because they do not exclude = or & characters.

    Note that by using .alphanumerics it will encode some characters that do not need to be encoded (like -, ., _ or ~ -– see 2.3. Unreserved characters in RFC 3986). I find using .alphanumerics simpler than constructing a custom character set and do not mind some additional characters to be encoded. If that bothers you, construct a custom character set as is described in How to percent encode a URL String, like for example:

    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: The encoded parameter is force unwrapped. For invalid unicode string it might crash. See Why is the return value of String.addingPercentEncoding() optional?. Instead of force unwrapping encoded! you can use encoded ?? "" or use if let encoded = ....

    0 讨论(0)
  • 2020-11-21 22:53

    What helped me was that I created a separate NSCharacterSet and used it on an UTF-8 encoded string i.e. textToEncode to generate the required result:

    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)"
    
    0 讨论(0)
  • 2020-11-21 22:54

    This is working for me in Swift 5. The usage case is taking a URL from the clipboard or similar which may already have escaped characters but which also contains Unicode characters which could cause URLComponents or URL(string:) to fail.

    First, create a character set that includes all URL-legal characters:

    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
        }
    }
    

    Next, extend String with a method to encode URLs:

    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
        }
    
    }
    

    Which can be tested like:

    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)
    

    Value of url at the end: 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

    Note that both %20 and + spacing are preserved, Unicode characters are encoded, the %20 in the original urlText is not double encoded, and the anchor (fragment, or #) remains.

    Edit: Now checking for validity of each component.

    0 讨论(0)
  • 2020-11-21 22:55

    Had need of this myself, so I wrote a String extension that both allows for URLEncoding strings, as well as the more common end goal, converting a parameter dictionary into "GET" style URL Parameters:

    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
        }
    }
    

    Enjoy!

    0 讨论(0)
  • 2020-11-21 22:55

    For Swift 5 to endcode string

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

    How to use ?

    let strEncoded = self.escape(string: "http://www.edamam.com/ontologies/edamam.owl#recipe_e2a1b9bf2d996cbd9875b80612ed9aa4")
    print("escapedString: \(strEncoded)")
    
    0 讨论(0)
提交回复
热议问题