How to use stringByAddingPercentEncodingWithAllowedCharacters() for a URL in Swift 2.0

StringSwiftSwift2Nscharacterset

String Problem Overview


I was using this, in Swift 1.2

let urlwithPercentEscapes = myurlstring.stringByAddingPercentEscapesUsingEncoding(NSUTF8StringEncoding)

This now gives me a warning asking me to use

stringByAddingPercentEncodingWithAllowedCharacters

I need to use a NSCharacterSet as an argument, but there are so many and I cannot determine what one will give me the same outcome as the previously used method.

An example URL I want to use will be like this

http://www.mapquestapi.com/geocoding/v1/batch?key=YOUR_KEY_HERE&callback=renderBatch&location=Pottsville,PA&location=Red Lion&location=19036&location=1090 N Charlotte St, Lancaster, PA

The URL Character Set for encoding seems to contain sets the trim my URL. i.e, > > The path component of a URL is the component immediately following the > host component (if present). It ends wherever the query or fragment > component begins. For example, in the URL > http://www.example.com/index.php?key1=value1, the path component is > /index.php.

However I don't want to trim any aspect of it. When I used my String, for example myurlstring it would fail.

But when used the following, then there were no issues. It encoded the string with some magic and I could get my URL data.

let urlwithPercentEscapes = myurlstring.stringByAddingPercentEscapesUsingEncoding(NSUTF8StringEncoding)

As it

> Returns a representation of the String using a given encoding to > determine the percent escapes necessary to convert the String into a > legal URL string

Thanks

String Solutions


Solution 1 - String

For the given URL string the equivalent to

let urlwithPercentEscapes = myurlstring.stringByAddingPercentEscapesUsingEncoding(NSUTF8StringEncoding)

is the character set URLQueryAllowedCharacterSet

let urlwithPercentEscapes = myurlstring.stringByAddingPercentEncodingWithAllowedCharacters( NSCharacterSet.URLQueryAllowedCharacterSet())

Swift 3:

let urlwithPercentEscapes = myurlstring.addingPercentEncoding( withAllowedCharacters: .urlQueryAllowed)

It encodes everything after the question mark in the URL string.

Since the method stringByAddingPercentEncodingWithAllowedCharacters can return nil, use optional bindings as suggested in the answer of Leo Dabus.

Solution 2 - String

It will depend on your url. If your url is a path you can use the character set urlPathAllowed

let myFileString = "My File.txt"
if let urlwithPercentEscapes = myFileString.addingPercentEncoding(withAllowedCharacters: .urlPathAllowed) {
    print(urlwithPercentEscapes)  // "My%20File.txt"
}

Creating a Character Set for URL Encoding

> urlFragmentAllowed > > urlHostAllowed > > urlPasswordAllowed > > urlQueryAllowed > > urlUserAllowed

You can create also your own url character set:

let myUrlString = "http://www.mapquestapi.com/geocoding/v1/batch?key=YOUR_KEY_HERE&callback=renderBatch&location=Pottsville,PA&location=Red Lion&location=19036&location=1090 N Charlotte St, Lancaster, PA"

let urlSet = CharacterSet.urlFragmentAllowed
                .union(.urlHostAllowed)
                .union(.urlPasswordAllowed)
                .union(.urlQueryAllowed)
                .union(.urlUserAllowed)

extension CharacterSet {
    static let urlAllowed = CharacterSet.urlFragmentAllowed
                                        .union(.urlHostAllowed)
                                        .union(.urlPasswordAllowed)
                                        .union(.urlQueryAllowed)
                                        .union(.urlUserAllowed)
}

if let urlwithPercentEscapes = myUrlString.addingPercentEncoding(withAllowedCharacters: .urlAllowed) {
    print(urlwithPercentEscapes)  // "http://www.mapquestapi.com/geocoding/v1/batch?key=YOUR_KEY_HERE&callback=renderBatch&location=Pottsville,PA&location=Red%20Lion&location=19036&location=1090%20N%20Charlotte%20St,%20Lancaster,%20PA"
}

Another option is to use URLComponents to properly create your url

Solution 3 - String

Swift 3.0 (From grokswift)

Creating URLs from strings is a minefield for bugs. Just miss a single / or accidentally URL encode the ? in a query and your API call will fail and your app won’t have any data to display (or even crash if you didn’t anticipate that possibility). Since iOS 8 there’s a better way to build URLs using NSURLComponents and NSURLQueryItems.

func createURLWithComponents() -> URL? {
        var urlComponents = URLComponents()
        urlComponents.scheme = "http"
        urlComponents.host = "www.mapquestapi.com"
        urlComponents.path = "/geocoding/v1/batch"
        
        let key = URLQueryItem(name: "key", value: "YOUR_KEY_HERE")
        let callback = URLQueryItem(name: "callback", value: "renderBatch")
        let locationA = URLQueryItem(name: "location", value: "Pottsville,PA")
        let locationB = URLQueryItem(name: "location", value: "Red Lion")
        let locationC = URLQueryItem(name: "location", value: "19036")
        let locationD = URLQueryItem(name: "location", value: "1090 N Charlotte St, Lancaster, PA")
      
        urlComponents.queryItems = [key, callback, locationA, locationB, locationC, locationD]
        
        return urlComponents.url
}

Below is the code to access url using guard statement.

guard let url = createURLWithComponents() else {
            print("invalid URL")
            return nil
      }
      print(url)

Output:

http://www.mapquestapi.com/geocoding/v1/batch?key=YOUR_KEY_HERE&callback=renderBatch&location=Pottsville,PA&location=Red%20Lion&location=19036&location=1090%20N%20Charlotte%20St,%20Lancaster,%20PA

Solution 4 - String

In Swift 3.1, I am using something like the following:

let query = "param1=value1&param2=" + valueToEncode.addingPercentEncoding(withAllowedCharacters: .alphanumeric)

It's safer than .urlQueryAllowed and the others, because it this will encode every characters other than A-Z, a-z and 0-9. This works better when the value you are encoding may use special characters like ?, &, =, + and spaces.

Solution 5 - String

In my case where the last component was non latin characters I did the following in Swift 2.2:

extension String {
 func encodeUTF8() -> String? {
//If I can create an NSURL out of the string nothing is wrong with it
if let _ = NSURL(string: self) {

    return self
}

//Get the last component from the string this will return subSequence
let optionalLastComponent = self.characters.split { $0 == "/" }.last


if let lastComponent = optionalLastComponent {

    //Get the string from the sub sequence by mapping the characters to [String] then reduce the array to String
    let lastComponentAsString = lastComponent.map { String($0) }.reduce("", combine: +)


    //Get the range of the last component
    if let rangeOfLastComponent = self.rangeOfString(lastComponentAsString) {
        //Get the string without its last component
        let stringWithoutLastComponent = self.substringToIndex(rangeOfLastComponent.startIndex)


        //Encode the last component
        if let lastComponentEncoded = lastComponentAsString.stringByAddingPercentEncodingWithAllowedCharacters(NSCharacterSet.alphanumericCharacterSet()) {


        //Finally append the original string (without its last component) to the encoded part (encoded last component)
        let encodedString = stringWithoutLastComponent + lastComponentEncoded

            //Return the string (original string/encoded string)
            return encodedString
        }
    }
}

return nil;
}
}

Solution 6 - String

Swift 4.0

let encodedData = myUrlString.addingPercentEncoding(withAllowedCharacters: CharacterSet.urlHostAllowed)

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionDogCoffeeView Question on Stackoverflow
Solution 1 - StringvadianView Answer on Stackoverflow
Solution 2 - StringLeo DabusView Answer on Stackoverflow
Solution 3 - StringAshok RView Answer on Stackoverflow
Solution 4 - StringBéatrice CassistatView Answer on Stackoverflow
Solution 5 - StringBobj-CView Answer on Stackoverflow
Solution 6 - StringSupertecnoboffView Answer on Stackoverflow