-->

Objective-C and Swift URL encoding

2019-01-01 00:09发布

问题:

I have a NSString like this:

http://www.

but I want to transform it to:

http%3A%2F%2Fwww.

How can I do this?

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



回答2:

It\'s called URL encoding. More here.

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


回答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.



回答4:

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

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


回答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)
                         );}


回答6:

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


回答7:

NSString *str = (NSString *)CFURLCreateStringByAddingPercentEscapes(
                             NULL,
                             (CFStringRef)yourString, 
                             NULL, 
                             CFSTR(\"/:\"), 
                             kCFStringEncodingUTF8);

You will need to release or autorelease str yourself.



回答8:

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).



回答9:

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!
    }
}


回答10:

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;
    }
}


回答11:

//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.



回答12:

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 );