385

If I encode a string like this:

var escapedString = originalString.stringByAddingPercentEscapesUsingEncoding(NSUTF8StringEncoding)

it doesn't escape the slashes /.

I've searched and found this Objective C code:

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

Is there an easier way to encode an URL and if not, how do I write this in Swift?

Bryan Chen
  • 45,816
  • 18
  • 112
  • 143
MegaCookie
  • 5,017
  • 3
  • 21
  • 25

19 Answers19

725

Swift 3

In Swift 3 there is addingPercentEncoding

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

Output:

test%2Ftest

Swift 1

In iOS 7 and above there is stringByAddingPercentEncodingWithAllowedCharacters

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

Output:

test%2Ftest

The following are useful (inverted) character sets:

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

If you want a different set of characters to be escaped create a set:
Example with added "=" character:

var originalString = "test/test=42"
var customAllowedSet =  NSCharacterSet(charactersInString:"=\"#%/<>?@\\^`{|}").invertedSet
var escapedString = originalString.stringByAddingPercentEncodingWithAllowedCharacters(customAllowedSet)
println("escapedString: \(escapedString)")

Output:

test%2Ftest%3D42

Example to verify ascii characters not in the set:

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)\'")
}
Linus Oleander
  • 17,746
  • 15
  • 69
  • 102
zaph
  • 111,848
  • 21
  • 189
  • 228
  • And if I want to add the equal sign too? – MegaCookie Jul 03 '14 at 17:44
  • Add a custom character set, I added an example. – zaph Jul 05 '14 at 03:51
  • 8
    Is no one else completely flabbergasted at how long this code is to do this? I mean that method name is already hell of long, even without choosing the allowed character set. – thatidiotguy Sep 30 '14 at 20:19
  • 52
    No, I favor understandability over short terse naming. Autocomplete takes the pain out. `stringByAddingPercentEncodingWithAllowedCharacters()` leaves little doubt about what it does. Interesting comment considering how long the word: "flabbergasted" is. – zaph Sep 30 '14 at 20:37
  • 1
    stringByAddingPercentEncodingWithAllowedCharacters(.URLHostAllowedCharacterSet()) Does not encode all character properly Bryan Chen's answer is a better solution. – Julio Garcia Jan 30 '16 at 16:54
  • @JulioGarcia either pick a character set based on the portion of the URL you are using or create a custom character set that matches your needs. Look at the `customAllowedSet` example. – zaph Jan 30 '16 at 16:58
  • Thanks Zaph, I just noticed that function it's been deprecated in iOS 9 – Julio Garcia Jan 30 '16 at 17:01
  • @zaph What about `&`? – Akash Kava Mar 02 '16 at 09:25
  • 1
    @AkashKava pick a character set that meets your needs of use `charactersInString:` to create a custom character set. – zaph Mar 02 '16 at 13:05
  • 2
    @zaph I added `&` to character set of `URLQueryAllowedCharacterSet` and I got each character encoded. Checked with iOS 9, looks like buggy, I went with @bryanchen's answer, it works well !! – Akash Kava Mar 02 '16 at 15:28
  • Why is Apple putting this method in the String class and not on NSURL? – user3246173 May 19 '16 at 16:25
  • 1
    That the method takes a string and returns a string is my best guess. – zaph May 19 '16 at 21:34
  • 1
    And of course, they've cleaned up the API a bit now. For example: let myEncodedString = myString.addingPercentEncoding(withAllowedCharacters: .urlQueryAllowed) – Ben Carroll Jun 27 '16 at 06:36
  • Your code doesn't encode `!` and some other special chacacters... why? – Konstantinos Natsios Oct 04 '16 at 15:22
  • Apple supplies several charactersets directed toward URL encoding. If you need to encode a different characterset than those supplied by Apple use the example of `customAllowedSet`. – zaph Oct 04 '16 at 15:36
  • 5
    The answer below that uses `URLComponents` and `URLQueryItem` is much cleaner IMO. – Aaron Brager Nov 12 '17 at 17:05
  • 1
    I used `CharacterSet(charactersIn: "=&").inverted` Thanks @zaph – Jack Mar 23 '18 at 11:15
  • Is it possible to back to test/test after conversion? – karthikeyan Feb 20 '20 at 13:52
  • all swift code is unnecessarily verbose. It's as bad as .NET library built-ins. too many primitive types too, but that's off topic. In js it's just encodeURIComponent, I don't know why the default in swift is to give you too many options, just encode for standard HTTP protocols and have separate parms for things you'd never use. – FlavorScape Feb 09 '21 at 00:18
104

You can use URLComponents to avoid having to manually percent encode your query string:

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
}
Leo Dabus
  • 229,809
  • 59
  • 489
  • 571
  • 7
    This answer needs more attention, as there are issues with all of the other ones (though to be fair they may have been best practice at the time). – Asa May 18 '17 at 14:55
  • 12
    Sadly, `URLQueryItem` does not always encode correctly. For example, `Formula+One` would be encoded to `Formula+One`, which would be decoded to `Formula One`. Therefore be cautious with the plus sign. – Sulthan Mar 10 '18 at 08:15
  • @Sulthan having a string "Formula+One" should be encoded to "Formula+One". This is because "+" is in the set of [Reserved Characters](https://datatracker.ietf.org/doc/html/rfc3986#section-2.2), which is included in the set of "pchar" which constitutes the query component. If the decoding would yield "Formula One" using URLComponents, then something is wrong ;) – CouchDeveloper Sep 29 '21 at 09:21
  • 1
    @CouchDeveloper This is a bit more complex than you think. Yu are quoting from URI spec but this is about URL, which is a special case. There are actually (at least) two URL specs with some conflicts. The URI spec itself says _"If data for a URI component would conflict with a reserved character's purpose as a delimiter, then the conflicting data must be percent-encoded before the URI is formed."_ This is obviously incorrect for `URLComponents` because a plus sign in URL-encoded output represents a space. – Sulthan Sep 29 '21 at 10:59
  • @Sulthan In the [URL spec](https://url.spec.whatwg.org) an URL query is defined as an ASCII string (with only rudimentary constraint checks in the serialiser and parser). To figure out the rules for parsing and serialising of a query which is a list of key value pairs, we need to look at [x-www-form-urlencoded](https://url.spec.whatwg.org/#application/x-www-form-urlencoded). Besides having some guidelines here, the spec itself says about x-www-form-urlencoded: "[this] format is in many ways an aberrant monstrosity, the result of many years of implementation accidents ..." ;) – CouchDeveloper Sep 29 '21 at 12:07
  • @Sulthan As far I have tested, URLComponents behaves correctly according the URI spec and according the rules defined in x-www-form-urlencoded: a plus sign "+" will not be encoded. In URLComponents, decode is the correct inverse to encode. – CouchDeveloper Sep 29 '21 at 12:33
  • @CouchDeveloper To put it simply. When you want to pass a phone number with international prefix, e.g. `+1....` to a GET request, you compose your query using `URLComponents` and then your server interprets the incoming `+` as a space, something is wrong. Foundation implementation works differently than the implementation in any other language (compare `encodeURIComponent` in javascript). Since this is the only implementation of URL-encoding in the library, I consider it a bug. – Sulthan Sep 29 '21 at 14:07
  • Yes, this is a problem. In the x-www-form-urlencoded, the decoding algorithm is NOT the inverse to the encoding function. It would, if the decoding would not unconditionally convert a "+" into a space, but just take it as is. Currently it MUST do this. Alternatively, it would be the inverse if the encoder would 1. _unconditionally_ convert spaces to "+" AND 2. percent encode "+". IMHO, this is a bummer. Note: 1. is optional. 2. is not possible unless redefining the query percent-encode set. – CouchDeveloper Sep 29 '21 at 15:43
86

Swift 4 & 5

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

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

Using any of the standard Character Sets for URL Encoding (like .urlQueryAllowed or .urlHostAllowed) 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:

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

Warning: The urlEncoded 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 urlEncoded! you can use urlEncoded ?? "" or if let urlEncoded = urlEncoded { ... }.

Marián Černý
  • 15,096
  • 4
  • 70
  • 83
  • 2
    .aphanumerics did the trick, thank you! All the other character sets didn't escape the &'s which caused problems when using the strings as get parameters. – Dion Dec 02 '19 at 14:32
  • 1
    Works on Swift 5.X and iOS14 – norbDEV Oct 30 '20 at 13:22
  • 1
    This should be the accepted answer. I wasted a bunch of time trying the other top answers which don't work with = characters. – GenericPtr Aug 31 '22 at 18:14
  • Why `.aphanumerics` instead of `.urlHostAllowed`? From the name, it sounds like it should encode `&`... Or is there another concern / advantage? – LinusGeffarth Oct 17 '22 at 09:05
  • Using `.urlHostAllowed` does not escape `=` or `&` characters, as written in the answer. Feel free to try it yourself. – Marián Černý Oct 24 '22 at 11:28
51

Swift 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


Hong Wei
  • 1,397
  • 1
  • 11
  • 16
50

Swift 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"
Uyghur Lives Matter
  • 18,820
  • 42
  • 108
  • 144
iHTCboy
  • 2,715
  • 21
  • 20
  • I used first solution but I want to my text back, like iOS开发工程师. – Akshay Phulare Jan 02 '18 at 13:38
  • 3
    Using `urlHostAllowed` for encoding query parameters in incorrect because it won't encode `?`, `=` and `+`. When encoding query parameters, you have to encode parameter name and value separately and correctly. This won't work in a general case. – Sulthan Jan 03 '19 at 14:18
  • @Sulthan.. Did you find any solution / alternative for `urlHostAllowed` – Bharath Jan 06 '19 at 10:31
  • @Bharath Yes, you have to build a character set by yourself, e.g. https://stackoverflow.com/a/39767927/669586 or just use `URLComponents`. – Sulthan Jan 06 '19 at 10:44
  • URLComponents don't encode the `+` char too. So the only option is to do it manually: `CharacterSet.urlQueryAllowed.subtracting(CharacterSet(charactersIn: "+"))` – SoftDesigner Apr 20 '20 at 15:29
  • it worked with hrebrew language(RTL language) url too – Munaf Sumbhaniya Sep 16 '20 at 13:46
30

Swift 4 & 5 (Thanks @sumizome for suggestion. Thanks @FD_ and @derickito for testing)

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 (Borrowing from Zaph's and correcting for url query key and parameter values)

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"

This is a shorter version of Bryan Chen's answer. I'd guess that urlQueryAllowed is allowing the control characters through which is fine unless they form part of the key or value in your query string at which point they need to be escaped.

AJP
  • 26,547
  • 23
  • 88
  • 127
  • 2
    I like the Swift 3 solution, but it does not work for me in Swift 4: "Cannot use mutating member on immutable value: 'urlQueryAllowed' is a get-only property". – Marián Černý Mar 09 '18 at 20:29
  • @MariánČerný just make the CharacterSet mutable (with `var`) and then call `.remove` on it in a second step. – sumizome Sep 25 '18 at 22:45
  • I believe this and most other solutions have issues when applying the method twice, eg when including an URL with encoded params in another URL's parameters. – FD_ Sep 14 '19 at 11:17
  • @FD_ do you know or do you just have a hunch? Can you experiment with it and post back? Would be good to include this info if so. Thank you. – AJP Sep 21 '19 at 11:35
  • 1
    @AJP I just tested all your snippets. Swift 3 and 4 work fine, but the one for Swift 2.2 doesn't properly encode %20 as %2520. – FD_ Sep 21 '19 at 12:29
  • 1
    Swift 4 solution works for me in July of 2020, using Swift 5 – derickito Jul 17 '20 at 21:03
  • Thanks @FD_ . Sorry I've only just seen this now. Any easy fix you can think of? – AJP Jul 18 '20 at 21:20
  • In Swift 5, with `.urlQueryAllowed`, seems only "&" is not removed by default – Harry Ng Mar 31 '21 at 02:21
17

Swift 4:

It depends by the encoding rules followed by your server.

Apple offer this class method, but it don't report wich kind of RCF protocol it follows.

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

Following this useful tool you should guarantee the encoding of these chars for your parameters:

  • $ (Dollar Sign) becomes %24
  • & (Ampersand) becomes %26
  • + (Plus) becomes %2B
  • , (Comma) becomes %2C
  • : (Colon) becomes %3A
  • ; (Semi-Colon) becomes %3B
  • = (Equals) becomes %3D
  • ? (Question Mark) becomes %3F
  • @ (Commercial A / At) becomes %40

In other words, speaking about URL encoding, you should following the RFC 1738 protocol.

And Swift don't cover the encoding of the + char for example, but it works well with these three @ : ? chars.

So, to correctly encoding each your parameter , the .urlHostAllowed option is not enough, you should add also the special chars as for example:

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

Hope this helps someone who become crazy to search these informations.

Community
  • 1
  • 1
Alessandro Ornano
  • 34,887
  • 11
  • 106
  • 133
14

Everything is same

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

// test%2Ftest
Bryan Chen
  • 45,816
  • 18
  • 112
  • 143
12

Swift 4.2

A quick one line solution. Replace originalString with the String you want to encode.

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

Online Playground Demo

andrewjazbec
  • 859
  • 8
  • 20
  • This worked thanks: you can check and try decode and encode results on. https://www.urldecoder.org – Rakshitha Muranga Rodrigo Mar 11 '20 at 22:44
  • 1
    I don't think this is a correct implementation. For example `let originalString = "\u{48}ello\u{9}world\u{7}\u{0}"` gets encoded to `"Hello\tworld\u{07}\0"`. E.g. control characters or a tabulator is not escaped. – Marián Černý May 12 '21 at 19:33
  • Worked for me, converted the + to %2B and other characters also. thank you. – Mike Nov 26 '22 at 14:48
6

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.

CartoonChess
  • 663
  • 7
  • 17
5

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)")
Hardik Thakkar
  • 15,269
  • 2
  • 94
  • 81
4

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!

BadPirate
  • 25,802
  • 10
  • 92
  • 123
3

This one is working for me.

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
}

I found above function from this link: http://useyourloaf.com/blog/how-to-percent-encode-a-url-string/.

Gaurav Singla
  • 2,271
  • 26
  • 43
2

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

jaskiratjd
  • 729
  • 1
  • 6
  • 16
2

None of these answers worked for me. Our app was crashing when a url contained non-English characters.

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

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

Depending on the parameters of what you are trying to do, you may want to just create your own character set. The above allows for english characters, and -._~/?%$!:

Jenel Ejercito Myers
  • 2,553
  • 2
  • 16
  • 24
2

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)"
Mohsin Khubaib Ahmed
  • 1,008
  • 16
  • 32
  • 1
    After 4 days of struggling this piece of code really helped. Thanks Mohsin. You are champ. Good luck and keep coding. Thanks once again. please upvote coders. – Amit Thakur Feb 21 '22 at 18:46
0

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.

Vrushal Raut
  • 1,050
  • 2
  • 15
  • 20
-2

version:Swift 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  
Lgufan
  • 95
  • 4
  • 1
    You say Swift 5 but then you use NSCharacterSet instead of CharacterSet, which is a weird choice. Also you're first replacing spaces with a + character but then in the list of characters to remove we see a space, so the first operation is redundant. – Eric Aya Apr 25 '21 at 09:34
  • use NSCharacterSet instead of CharacterSet,that because refer to other answers.@EricAya – Lgufan Apr 27 '21 at 06:00
  • `+` can be used to represent a space, but existing instances of `+` need to be properly escaped. This answer is an example of what not to do. – Robin Daugherty Feb 19 '23 at 14:00
-4

Swift 5 You can try .afURLQueryAllowed option if you want to encode string like below

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

//encoded string will be like en6hAD9%2FRjY%2BSnGm%26B

9to5ios
  • 5,319
  • 2
  • 37
  • 65
Dilip
  • 349
  • 2
  • 9