141

I have a NSString like this:

http://www.

but I want to transform it to:

http%3A%2F%2Fwww.

How can I do this?

zaph
  • 111,848
  • 21
  • 189
  • 228
Usi Usi
  • 2,967
  • 5
  • 38
  • 69
  • 1
    I have an encrypted string like `ùÕ9y^VêÏÊEØ®.ú/V÷ÅÖêú2Èh~` - none of the solutions below seems to address this! – Mahendra Liya Oct 12 '13 at 06:27

13 Answers13

336

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 \"%-.<>\^_`{|}~"

zaph
  • 111,848
  • 21
  • 189
  • 228
  • 1
    Also note you can use NSString's `-stringByAddingPercentEscapesUsingEncoding` method. – Mike Weller Jun 14 '12 at 14:26
  • 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 Jun 14 '12 at 14:30
  • 2
    Ah yes, now I remember the funky `stringByAddingPercentEscapesUsingEncoding` behaviour. It only encodes '&' and '=' or something ridiculous like that. – Mike Weller Jun 14 '12 at 14:45
  • Under ARC the initial answer does leak and the suggestion by @Mike is correct, I have added alternatives for use under ARC. – zaph Jun 14 '12 at 15:03
  • also under ARC you would need to set the bridge for the unescaped string: ... (__bridge CFStringRef) unescaped, ... – Praveen Jul 30 '12 at 01:33
  • 2
    According to [RFC1738](http://www.ietf.org/rfc/rfc1738.txt) 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. – Alex Nauda Aug 05 '13 at 20:26
  • Maybe for more usability, should the solution contain the space and quote characters? Something like `CFSTR("!*'();:@&=+$,/?%#[]\" ")` – lgdev Nov 07 '13 at 16:55
  • 3
    This doesn't work (for iOS 7 part). This doesn't convert & into %26. – coolcool1994 Jul 14 '14 at 16:52
  • 1
    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](http://stackoverflow.com/a/24552028/451475). – zaph Jul 14 '14 at 17:34
  • 1
    [The Apple documentation](https://developer.apple.com/library/ios/documentation/Cocoa/Conceptual/URLLoadingSystem/WorkingwithURLEncoding/WorkingwithURLEncoding.html) says: `Important: Although the NSString class provides built-in methods for adding percent escapes, you usually should not use them.` – lifeisfoo Jun 25 '15 at 11:21
24

It's called URL encoding. More here.

-(NSString *)urlEncodeUsingEncoding:(NSStringEncoding)encoding {
    return (NSString *)CFURLCreateStringByAddingPercentEscapes(NULL,
           (CFStringRef)self,
           NULL,
           (CFStringRef)@"!*'\"();:@&=+$,/?%#[]% ",
           CFStringConvertNSStringEncodingToEncoding(encoding));
}
larsacus
  • 7,346
  • 3
  • 26
  • 23
  • 3
    This would be a lot more useful if some content from the links you posted were included in the answer. – chown Nov 11 '11 at 01:43
  • 1
    `CFURLCreateStringByAddingPercentEscapes()` is deprecated. Use `[NSString stringByAddingPercentEncodingWithAllowedCharacters:]` instead. – Pang Mar 09 '17 at 06:39
7

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.

Anonymous White
  • 2,149
  • 3
  • 20
  • 27
  • Original code: http://stackoverflow.com/questions/3423545/objective-c-iphone-percent-encode-a-string/3426140#3426140 – hsoi Nov 15 '13 at 21:11
  • what is [self UTF8String] ? – Yuchao Zhou Jun 01 '16 at 14:29
  • 1
    @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. – Kelsey Jun 02 '16 at 17:02
4
 NSString * encodedString = (NSString *)CFURLCreateStringByAddingPercentEscapes(NUL,(CFStringRef)@"parameter",NULL,(CFStringRef)@"!*'();@&+$,/?%#[]~=_-.:",kCFStringEncodingUTF8 );

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

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)
                         );}
Neuneed
  • 39
  • 4
3

Here's what I use. Note you have to use the @autoreleasepool feature or the program might crash or lockup the IDE. I had to restart my IDE three times until I realized the fix. It appears that this code is ARC compliant.

This question has been asked many times, and many answers given, but sadly all of the ones selected (and a few others suggested) are wrong.

Here's the test string that I used: This is my 123+ test & test2. Got it?!

These are my Objective C++ class methods:

static NSString * urlDecode(NSString *stringToDecode) {
    NSString *result = [stringToDecode stringByReplacingOccurrencesOfString:@"+" withString:@" "];
    result = [result stringByReplacingPercentEscapesUsingEncoding:NSUTF8StringEncoding];
    return result;
}

static NSString * urlEncode(NSString *stringToEncode) {
    @autoreleasepool {
        NSString *result = (NSString *)CFBridgingRelease(CFURLCreateStringByAddingPercentEscapes(
                NULL,
                (CFStringRef)stringToEncode,
                NULL,
                (CFStringRef)@"!*'\"();:@&=+$,/?%#[]% ",
                kCFStringEncodingUTF8
            ));
        result = [result stringByReplacingOccurrencesOfString:@"%20" withString:@"+"];
        return result;
    }
}
Volomike
  • 23,743
  • 21
  • 113
  • 209
2

Swift iOS:

Just For Information : I have used this:

extension String {

    func urlEncode() -> CFString {
        return CFURLCreateStringByAddingPercentEscapes(
            nil,
            self,
            nil,
            "!*'();:@&=+$,/?%#[]",
            CFStringBuiltInEncodings.UTF8.rawValue
        )
    }

}// end extension String
Vinod Joshi
  • 7,696
  • 1
  • 50
  • 51
1
NSString *str = (NSString *)CFURLCreateStringByAddingPercentEscapes(
                             NULL,
                             (CFStringRef)yourString, 
                             NULL, 
                             CFSTR("/:"), 
                             kCFStringEncodingUTF8);

You will need to release or autorelease str yourself.

elp
  • 8,021
  • 7
  • 61
  • 120
Wevah
  • 28,182
  • 7
  • 83
  • 72
0

Google implements this in their Google Toolbox for Mac. So that's a good place to peak how they're doing it. Another option is to include the Toolbox and use their implementation.

Checkout the implementation here. (Which comes down to exactly what people have been posting here).

wrtsprt
  • 5,319
  • 4
  • 21
  • 30
0

This is how I am doing this in swift.

extension String {
    func encodeURIComponent() -> String {
        return self.stringByAddingPercentEncodingWithAllowedCharacters(NSCharacterSet.URLQueryAllowedCharacterSet())!
    }

    func decodeURIComponent() -> String {
        return self.componentsSeparatedByString("+").joinWithSeparator(" ").stringByRemovingPercentEncoding!
    }
}
Andrew
  • 3,733
  • 1
  • 35
  • 36
0

This is what I did on Swift 5:

func formatPassword() -> String {
    
    var output = "";

    for ch in self {

        let char = String(ch)

        switch ch {

            case " ":
                output.append("+")

                break

            case ".", "-", "_", "~", "a"..."z", "A"..."Z", "0"..."9":

                output.append(char)

                break

                default:

                print(ch)

                let unicode = char.unicodeScalars.first?.value ?? 0

                let unicodeValue = NSNumber(value: unicode).intValue

                let hexValue = String(format: "%02X", arguments: [unicodeValue])

                output = output.appendingFormat("%%%@", hexValue)

                }

            }
    
    return output as String
}

Then I called this function where I defined my password.

koen
  • 5,383
  • 7
  • 50
  • 89
-1

//use NSString instance method like this:

+ (NSString *)encodeURIComponent:(NSString *)string
{
NSString *s = [string stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding];
return s;
}

+ (NSString *)decodeURIComponent:(NSString *)string
{
NSString *s = [string stringByReplacingPercentEscapesUsingEncoding:NSUTF8StringEncoding];
return s;
}

remember,you should only do encode or decode for your parameter value, not all the url you request.

lingtianlan
  • 304
  • 2
  • 7
-8
int strLength = 0;
NSString *urlStr = @"http://www";
NSLog(@" urlStr : %@", urlStr );
NSMutableString *mutableUrlStr = [urlStr mutableCopy];
NSLog(@" mutableUrlStr : %@", mutableUrlStr );
strLength = [mutableUrlStr length];
[mutableUrlStr replaceOccurrencesOfString:@":" withString:@"%3A" options:NSCaseInsensitiveSearch range:NSMakeRange(0, strLength)];
NSLog(@" mutableUrlStr : %@", mutableUrlStr );
strLength = [mutableUrlStr length];
[mutableUrlStr replaceOccurrencesOfString:@"/" withString:@"%2F" options:NSCaseInsensitiveSearch range:NSMakeRange(0, strLength)];
NSLog(@" mutableUrlStr : %@", mutableUrlStr );
ader
  • 5,403
  • 1
  • 21
  • 26