If you use stringByAddingPercentEscapesUsingEncoding:
more than once on a string, the resulting string will not decode correctly from just one call to stringByReplacingPercentEscapesUsingEncoding:
. (stringByAddingPercentEscapesUsingEncoding: is not indempotent).
NSString *string = @"100%";
NSString *escapedOnce = [string stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding];
NSString *escapedTwice = [escapedOnce stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding];
NSLog(@"%@ escaped once: %@, escaped twice: %@", string, escapedOnce, escapedTwice);
100% escaped once: 100%25, escaped twice: 100%2525
I thought I was programming defensively by eagerly adding percent-escapes to any string that would become part of a URL. But this caused some annoying bugs resulting form a string being percent-escaped more then once. My solution was to create an indempotent replacement for stringByAddingPercentEscapesUsingEncoding:
(I also simplified things a little by removing the encoding parameter, because I never used any encoding other then NSUTF8StringEncoding
),
@implementation NSString (IndempotentPercentEscapes)
- (NSString*) stringByReplacingPercentEscapesOnce;
{
NSString *unescaped = [self stringByReplacingPercentEscapesUsingEncoding:NSUTF8StringEncoding];
//self may be a string that looks like an invalidly escaped string,
//eg @"100%", in that case it clearly wasn't escaped,
//so we return it as our unescaped string.
return unescaped ? unescaped : self;
}
- (NSString*) stringByAddingPercentEscapesOnce;
{
return [[self stringByReplacingPercentEscapesOnce] stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding];
}
@end
Usage example,
NSString *string = @"100%";
NSString *escapedOnce = [string stringByAddingPercentEscapesOnce];
NSString *escapedTwice = [escapedOnce stringByAddingPercentEscapesOnce];
NSLog(@"%@ escaped once: %@, escaped twice: %@", string, escapedOnce, escapedTwice);
100% escaped once: 100%25, escaped twice: 100%25
The paranoid have probably noticed that [aBadlyEncodedString stringByReplacingPercentEscapesOnce]
will return aBadlyEncodedString
not nil
, This could make it harder to detect an error.
But it’s not something that I’m worried about for my application. Since I only ever use a UTF8 encoding, and it can represent any unicode character, it’s not possible to have an invalid string. But it’s certainly something to be aware of in situations where you might have strings with different encodings.