Objective-C and Swift URL encoding

116,921

Solution 1

To escape the characters you want is a little more work.

Example code

iOS7 and above:

NSString *unescaped = @"http://www";
NSString *escapedString = [unescaped stringByAddingPercentEncodingWithAllowedCharacters:[NSCharacterSet URLHostAllowedCharacterSet]];
NSLog(@"escapedString: %@", escapedString);

NSLog output:

escapedString: http%3A%2F%2Fwww

The following are useful URL encoding character sets:

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

Creating a characterset combining all of the above:

NSCharacterSet *URLCombinedCharacterSet = [[NSCharacterSet characterSetWithCharactersInString:@" \"#%/:<>?@[\\]^`{|}"] invertedSet];

Creating a Base64

In the case of Base64 characterset:

NSCharacterSet *URLBase64CharacterSet = [[NSCharacterSet characterSetWithCharactersInString:@"/+=\n"] invertedSet];

For Swift 3.0:

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

For Swift 2.x:

var escapedString = originalString.stringByAddingPercentEncodingWithAllowedCharacters(NSCharacterSet.URLHostAllowedCharacterSet())

Note: stringByAddingPercentEncodingWithAllowedCharacters will also encode UTF-8 characters needing encoding.

Pre iOS7 use Core Foundation
Using Core Foundation With ARC:

NSString *escapedString = (NSString *)CFBridgingRelease(CFURLCreateStringByAddingPercentEscapes(
    NULL,
   (__bridge CFStringRef) unescaped,
    NULL,
    CFSTR("!*'();:@&=+$,/?%#[]\" "),
    kCFStringEncodingUTF8));

Using Core Foundation Without ARC:

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

Note: -stringByAddingPercentEscapesUsingEncoding will not produce the correct encoding, in this case it will not encode anything returning the same string.

stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding encodes 14 characrters:

`#%^{}[]|\"<> plus the space character as percent escaped.

testString:

" `~!@#$%^&*()_+-={}[]|\\:;\"'<,>.?/AZaz"  

encodedString:

"%20%60~!@%23$%25%5E&*()_+-=%7B%7D%5B%5D%7C%5C:;%22'%3C,%3E.?/AZaz"  

Note: consider if this set of characters meet your needs, if not change them as needed.

RFC 3986 characters requiring encoding (% added since it is the encoding prefix character):

"!#$&'()*+,/:;=?@[]%"

Some "unreserved characters" are additionally encoded:

"\n\r \"%-.<>\^_`{|}~"

Solution 2

It's called URL encoding. More here.

-(NSString *)urlEncodeUsingEncoding:(NSStringEncoding)encoding {
    return (NSString *)CFURLCreateStringByAddingPercentEscapes(NULL,
           (CFStringRef)self,
           NULL,
           (CFStringRef)@"!*'\"();:@&=+$,/?%#[]% ",
           CFStringConvertNSStringEncodingToEncoding(encoding));
}

Solution 3

This is not my solution. Someone else wrote in stackoverflow but I have forgotten how.

Somehow this solution works "well". It handles diacritic, chinese characters, and pretty much anything else.

- (NSString *) URLEncodedString {
    NSMutableString * output = [NSMutableString string];
    const char * source = [self UTF8String];
    int sourceLen = strlen(source);
    for (int i = 0; i < sourceLen; ++i) {
        const unsigned char thisChar = (const unsigned char)source[i];
        if (false && thisChar == ' '){
            [output appendString:@"+"];
        } else if (thisChar == '.' || thisChar == '-' || thisChar == '_' || thisChar == '~' ||
                   (thisChar >= 'a' && thisChar <= 'z') ||
                   (thisChar >= 'A' && thisChar <= 'Z') ||
                   (thisChar >= '0' && thisChar <= '9')) {
            [output appendFormat:@"%c", thisChar];
        } else {
            [output appendFormat:@"%%%02X", thisChar];
        }
    }
    return output;
}

If someone would tell me who wrote this code, I'll really appreciate it. Basically he has some explanation why this encoded string will decode exactly as it wish.

I modified his solution a little. I like space to be represented with %20 rather than +. That's all.

Solution 4

 NSString * encodedString = (NSString *)CFURLCreateStringByAddingPercentEscapes(NUL,(CFStringRef)@"parameter",NULL,(CFStringRef)@"!*'();@&+$,/?%#[]~=_-.:",kCFStringEncodingUTF8 );

NSURL * url = [[NSURL alloc] initWithString:[@"address here" stringByAppendingFormat:@"?cid=%@",encodedString, nil]];

Solution 5

This can work in Objective C ARC.Use CFBridgingRelease to cast a Core Foundation-style object as an Objective-C object and transfer ownership of the object to ARC .See Function CFBridgingRelease here.

+ (NSString *)encodeUrlString:(NSString *)string {
return CFBridgingRelease(CFURLCreateStringByAddingPercentEscapes
                         (kCFAllocatorDefault,
                          (__bridge CFStringRef)string,
                          NULL,
                          CFSTR("!*'();:@&=+$,/?%#[]"),
                          kCFStringEncodingUTF8)
                         );}
Share:
116,921
Usi Usi
Author by

Usi Usi

Updated on July 08, 2022

Comments

  • Usi Usi
    Usi Usi almost 2 years

    I have a NSString like this:

    http://www.
    

    but I want to transform it to:

    http%3A%2F%2Fwww.
    

    How can I do this?

  • chown
    chown over 12 years
    This would be a lot more useful if some content from the links you posted were included in the answer.
  • Mike Weller
    Mike Weller almost 12 years
    Also note you can use NSString's -stringByAddingPercentEscapesUsingEncoding method.
  • Mike Weller
    Mike Weller almost 12 years
    This code also leaks memory unless you use a __bridge_retained cast under ARC, or call CFRelease at some point on the return value from CFURLCreateStringByAddingPercentEscapes.
  • Mike Weller
    Mike Weller almost 12 years
    Ah yes, now I remember the funky stringByAddingPercentEscapesUsingEncoding behaviour. It only encodes '&' and '=' or something ridiculous like that.
  • zaph
    zaph almost 12 years
    Under ARC the initial answer does leak and the suggestion by @Mike is correct, I have added alternatives for use under ARC.
  • Praveen
    Praveen almost 12 years
    also under ARC you would need to set the bridge for the unescaped string: ... (__bridge CFStringRef) unescaped, ...
  • Zahi
    Zahi over 11 years
    release encodedString and url. this code is about encode parameter. To encode whole address pass string instead of "parameter".
  • Sébastien Stormacq
    Sébastien Stormacq over 11 years
    stringByReplacingPercentEscapeusingencoding: only escapes & and = :-(
  • Alex Nauda
    Alex Nauda almost 11 years
    According to RFC1738 you would need to encode additional characters as well. So although this does answer the OP's question, it has limited usefulness as a general-purpose URL encoder. For example, it doesn't handle non-alphanumerics such as a German umlaut.
  • John Ballinger
    John Ballinger over 10 years
    Correct, so things like + are not encoded, when they need to be. So dont use the above answer
  • lgdev
    lgdev over 10 years
    Maybe for more usability, should the solution contain the space and quote characters? Something like CFSTR("!*'();:@&=+$,/?%#[]\" ")
  • zaph
    zaph over 10 years
    @Luka Updated answer.
  • hsoi
    hsoi over 10 years
  • coolcool1994
    coolcool1994 almost 10 years
    This doesn't work (for iOS 7 part). This doesn't convert & into %26.
  • zaph
    zaph almost 10 years
    Create the character set you need from an NSString with characterSetWithCharactersInString, take the inverse with invertedSet and use that with stringByAddingPercentEncodingWithAllowedCharacters. For an example see this SO answer.
  • lifeisfoo
    lifeisfoo almost 9 years
    The Apple documentation says: Important: Although the NSString class provides built-in methods for adding percent escapes, you usually should not use them.
  • Виктор Иванов
    Виктор Иванов almost 9 years
    This worked for me... encoded even the & character that I was having issues with.
  • Yuchao Zhou
    Yuchao Zhou almost 8 years
    what is [self UTF8String] ?
  • Kelsey
    Kelsey almost 8 years
    @yuchaozh this is a function that you put inside a category of NSString. So, self is NSStirng and [self UTF8String] returns, assumingly, its string in UTF8 format.
  • Pang
    Pang about 7 years
    CFURLCreateStringByAddingPercentEscapes() is deprecated. Use [NSString stringByAddingPercentEncodingWithAllowedCharacters:] instead.