views:

141

answers:

3

I would like to get the percent encoded string for these specific letters, how to do that in objective-c?

Reserved characters after percent-encoding
!   *   '   (   )   ;   :   @   &   =   +   $   ,   /   ?   #   [   ]
%21 %2A %27 %28 %29 %3B %3A %40 %26 %3D %2B %24 %2C %2F %3F %23 %5B %5D

Percent-encoding wiki

Please test with this string and see if it do work:

myURL = @"someurl/somecontent"

I would like the string to look like:

myEncodedURL = @"someurl%2Fsomecontent"

I tried with the stringByAddingPercentEscapesUsingEncoding: NSASCIIStringEncoding already but it does not work, the result is still the same as the original string. Please advice.

A: 

NSString's stringByAddingPercentEscapesUsingEncoding: looks like what you're after.

EDIT: Here's an example using CFURLCreateStringByAddingPercentEscapes instead. originalString can be either an NSString or a CFStringRef.

CFStringRef newString = CFURLCreateStringByAddingPercentEscapes(kCFAllocatorDefault, originalString, NULL, CFSTR("!*'();:@&=+@,/?#[]"), kCFStringEncodingUTF8);

Please note that this is untested. You should have a look at the documentation page to make sure you understand the memory allocation semantics for CFStringRef, the idea of toll-free bridging, and so on.

Also, I don't know (off the top of my head) which of the characters specified in the legalURLCharactersToBeEscaped argument would have been escaped anyway (due to being illegal in URLs). You may want to check this, although it's perhaps better just to be on the safe side and directly specify the characters you want escaped.

I'm making this answer a community wiki so that people with more knowledge about CoreFoundation can make improvements.

David
Which NSStringEcoding do I have to use to make all those characters above work correctly? Have you tried with a string?
sfa
Hmm, there doesn't seem to be an `NSStringEncoding` value for what you want. You could try `CFURLCreateStringByAddingPercentEscapes` (http://developer.apple.com/mac/library/documentation/CoreFoundation/Reference/CFURLRef/Reference/reference.html#//apple_ref/c/func/CFURLCreateStringByAddingPercentEscapes) instead - it lets you directly specify the characters to escape.
David
...oh, and by the way: `NSString` and `CFStringRef` are "toll-free bridged", meaning that they can be passed interchangeably to each other's functions.
David
so, how do I do that? Can you edit your answer, please?
sfa
A: 
NSString *encodedString = [myString stringByAddingPercentEscapesUsingEncoding:NSASCIIStringEncoding];

It won't replace your string inline; it'll return a new string. That's implied by the fact that the method starts with the word "string". It's a convenience method to instantiate a new instance of NSString based on the current NSString.

Note--that new string will be autorelease'd, so don't call release on it when you're done with it.

Dan Ray
Thanks, but it does not work, please check my updated question.
sfa
What did it do?
Dan Ray
the result is still the same, there's no change.
sfa
+3  A: 

I've found that both stringByAddingPercentEscapesUsingEncoding: and CFURLCreateStringByAddingPercentEscapes() are inadequate. The NSString method misses quite a few characters, and the CF function only lets you say which (specific) characters you want to escape. The proper specification is to escape all characters except a small set.

To fix this, I created an NSString category method to properly encode a string. It will percent encoding everything EXCEPT [a-zA-Z0-9.-_~] and will also encode spaces as + (according to this specification). It will also properly handle encoding unicode characters.

- (NSString *) URLEncodedString_ch {
    NSMutableString * output = [NSMutableString string];
    const unsigned char * source = (const unsigned char *)[self UTF8String];
    int sourceLen = strlen((const char *)source);
    for (int i = 0; i < sourceLen; ++i) {
        const unsigned char thisChar = source[i];
        if (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;
}
Dave DeLong
Dave, you rock!
sfa