23

How do we pass a string Mr.X & Mr.Y in the URL.

I have tried this but this one does all the chars but ampersand.

[urlString stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding]
Cœur
  • 37,241
  • 25
  • 195
  • 267

6 Answers6

36

Or even shorter:

@implementation NSString (Escaping)
- (NSString*)stringWithPercentEscape {            
    return [(NSString *) CFURLCreateStringByAddingPercentEscapes(
        NULL, 
        (CFStringRef)[[self mutableCopy] autorelease], 
        NULL, 
        CFSTR("=,!$&'()*+;@?\n\"<>#\t :/"),
        kCFStringEncodingUTF8) autorelease];
}
@end

And here it is again as an ARC conform inline function helper:

#if __has_feature(objc_arc)
static inline NSString *hxURLEscape(NSString *v) {
    static CFStringRef _hxURLEscapeChars = CFSTR("=,!$&'()*+;@?\r\n\"<>#\t :/");
    return ((__bridge_transfer NSString *)CFURLCreateStringByAddingPercentEscapes(
        NULL, 
        (__bridge CFStringRef)[v mutableCopy], 
        NULL, 
        _hxURLEscapeChars, 
        kCFStringEncodingUTF8));
}
#endif
Holtwick
  • 1,849
  • 23
  • 29
  • Please see Roger's answer below. While this solution is a good general answer, it is not a complete URL encoding implementation as of iOS version 2.2. If anyone has any additional information about this being fixed in later iOS releases, please comment here. – memmons Aug 02 '10 at 20:05
  • 2
    Indeed, I think we don't even need to copy it at all and can replace `[[self mutableCopy] autorelease]` by `self`. More details about it are available in the documentation of `CFURLCreateStringByAddingPercentEscapes ` http://developer.apple.com/library/mac/#documentation/CoreFoundation/Reference/CFURLRef/Reference/reference.html – Holtwick Aug 01 '11 at 19:23
  • Good article about the issue http://www.mikeabdullah.net/escaping-url-paths-in-cocoa.html – Holtwick Jul 19 '13 at 05:21
32

-stringByAddingPercentEscapesUsingEncoding: does not perform complete escape encoding. You should manually add the encodings using -replaceOccurrencesOfString:withString:

Here's a complete list (mirroring Gamecat's list) as originally suggested at https://devforums.apple.com/message/15674#15674. As Nick points out, this is expensive so do not simply include the full list without considering your real requirements for escaping.

NSMutableString *escaped = [actionString stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding];   
[escaped replaceOccurrencesOfString:@"$" withString:@"%24" options:NSCaseInsensitiveSearch range:wholeString];
[escaped replaceOccurrencesOfString:@"&" withString:@"%26" options:NSCaseInsensitiveSearch range:wholeString];
[escaped replaceOccurrencesOfString:@"+" withString:@"%2B" options:NSCaseInsensitiveSearch range:wholeString];
[escaped replaceOccurrencesOfString:@"," withString:@"%2C" options:NSCaseInsensitiveSearch range:wholeString];
[escaped replaceOccurrencesOfString:@"/" withString:@"%2F" options:NSCaseInsensitiveSearch range:wholeString];
[escaped replaceOccurrencesOfString:@":" withString:@"%3A" options:NSCaseInsensitiveSearch range:wholeString];
[escaped replaceOccurrencesOfString:@";" withString:@"%3B" options:NSCaseInsensitiveSearch range:wholeString];
[escaped replaceOccurrencesOfString:@"=" withString:@"%3D" options:NSCaseInsensitiveSearch range:wholeString];
[escaped replaceOccurrencesOfString:@"?" withString:@"%3F" options:NSCaseInsensitiveSearch range:wholeString];
[escaped replaceOccurrencesOfString:@"@" withString:@"%40" options:NSCaseInsensitiveSearch range:wholeString];
[escaped replaceOccurrencesOfString:@" " withString:@"%20" options:NSCaseInsensitiveSearch range:wholeString];
[escaped replaceOccurrencesOfString:@"\t" withString:@"%09" options:NSCaseInsensitiveSearch range:wholeString];
[escaped replaceOccurrencesOfString:@"#" withString:@"%23" options:NSCaseInsensitiveSearch range:wholeString];
[escaped replaceOccurrencesOfString:@"<" withString:@"%3C" options:NSCaseInsensitiveSearch range:wholeString];
[escaped replaceOccurrencesOfString:@">" withString:@"%3E" options:NSCaseInsensitiveSearch range:wholeString];
[escaped replaceOccurrencesOfString:@"\"" withString:@"%22" options:NSCaseInsensitiveSearch range:wholeString];
[escaped replaceOccurrencesOfString:@"\n" withString:@"%0A" options:NSCaseInsensitiveSearch range:wholeString];

This code certainly makes a hash of your URL.

Rog
  • 17,070
  • 9
  • 50
  • 73
  • 8
    I believe the proper code would be more like NSMutableString *escaped = [NSMutableString stringWithString:[actionString ...]]; and NSMakeRange(0, [escaped length])] instead of wholeString. – kolinko Oct 13 '10 at 05:44
  • 1
    This is quite costly, CFURLCreateStringByAddingPercentEscapes() is better. – Nick Toumpelis Oct 17 '12 at 09:48
  • Does CFURLCreateStringByAddingPercentEscapes not have the same problems as stringByAddingPercentEscapesUsingEncoding? – Rog Oct 17 '12 at 09:55
5

Use %26 as url escape.

Other escapes:

$  %24
&  %26
+  %2B
,  %2C
/  %2F
:  %3A
;  %3B
=  %3D
?  %3F
@  %40
Toon Krijthe
  • 52,876
  • 38
  • 145
  • 202
  • So If I do the following am I right [statusTextField.text stringByReplacingOccurrencesOfString:@"&" withString:@"%26"] and on my server side I replace %26 with & and store in the db. –  Apr 01 '09 at 14:19
0

stringByAddingPercentEscapesUsingEncoding also doesn't work properly with +.

Here is a simpler solution:

[[[urlString stringByAddingPercentEscapesUsingEncoding:NSASCIIStringEncoding] stringByReplacingOccurrencesOfString:@"&" withString:@"%26"] stringByReplacingOccurrencesOfString:@"+" withString:@"%2b"];
Pero P.
  • 25,813
  • 9
  • 61
  • 85
CpnCrunch
  • 4,831
  • 1
  • 33
  • 31
0

CFURLCreateStringByAddingPercentEscapes is deprecated (since iOS9), so how about just modifying the URLQueryAllowedCharacterSet to remove the reserved characters, thereby allowing them to be percent encoded relatively efficiently?

- (NSString *)URLQueryValueEncodedString:(NSString *)string {
    static NSMutableCharacterSet *_allowedCharacterSet = nil;
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        NSString *reservedCharacters = @"=,!$&'()*+;@?\r\n\"<>#\t :/[]%";
        _allowedCharacterSet = [NSCharacterSet URLQueryAllowedCharacterSet].mutableCopy;
        [_allowedCharacterSet removeCharactersInString:reservedCharacters];
    });

    return [string stringByAddingPercentEncodingWithAllowedCharacters:_allowedCharacterSet];
}
siburb
  • 4,880
  • 1
  • 25
  • 34
-2

In a URL, the ampersand is a protected keyword signifying the inclusion of a querystring variable. You cannot put it in as part of the value itself. You need to change it to something else.

Here is a link to the same question asked on StackOverflow: ASP.Net URLEncode Ampersand for use in Query String

Community
  • 1
  • 1
Tacoman667
  • 1,391
  • 9
  • 16