Кодирование URL-адресов Objective-C и Swift

140

У меня NSStringтакая:

http://www.

но я хочу преобразовать его в:

http%3A%2F%2Fwww.

Как я могу это сделать?

Usi Usi
источник
1
У меня есть зашифрованная строка вроде ùÕ9y^VêÏÊEØ®.ú/V÷ÅÖêú2Èh~- ни одно из приведенных ниже решений не решает эту проблему!
Махендра Лия

Ответы:

327

Чтобы избежать нужных вам персонажей, потребуется немного больше работы.

Пример кода

iOS7 и выше:

NSString *unescaped = @"http://www";
NSString *escapedString = [unescaped stringByAddingPercentEncodingWithAllowedCharacters:[NSCharacterSet URLHostAllowedCharacterSet]];
NSLog(@"escapedString: %@", escapedString);

Вывод NSLog:

escapedString: http% 3A% 2F% 2Fwww

Ниже приведены полезные наборы символов кодировки URL:

URLFragmentAllowedCharacterSet  "#%<>[\]^`{|}
URLHostAllowedCharacterSet      "#%/<>?@\^`{|}
URLPasswordAllowedCharacterSet  "#%/:<>?@[\]^`{|}
URLPathAllowedCharacterSet      "#%;<>?[\]^`{|}
URLQueryAllowedCharacterSet     "#%<>[\]^`{|}
URLUserAllowedCharacterSet      "#%/:<>?@[\]^`

Создание набора символов, сочетающего все вышеперечисленное:

NSCharacterSet *URLCombinedCharacterSet = [[NSCharacterSet characterSetWithCharactersInString:@" \"#%/:<>?@[\\]^`{|}"] invertedSet];

Создание Base64

В случае набора символов Base64:

NSCharacterSet *URLBase64CharacterSet = [[NSCharacterSet characterSetWithCharactersInString:@"/+=\n"] invertedSet];

Для Swift 3.0:

var escapedString = originalString.addingPercentEncoding(withAllowedCharacters:.urlHostAllowed)

Для Swift 2.x:

var escapedString = originalString.stringByAddingPercentEncodingWithAllowedCharacters(NSCharacterSet.URLHostAllowedCharacterSet())

Примечание: stringByAddingPercentEncodingWithAllowedCharactersтакже будут кодироваться символы UTF-8, требующие кодировки.

До iOS7 использовалось Core Foundation
Использование Core Foundation с ARC:

NSString *escapedString = (NSString *)CFBridgingRelease(CFURLCreateStringByAddingPercentEscapes(
    NULL,
   (__bridge CFStringRef) unescaped,
    NULL,
    CFSTR("!*'();:@&=+$,/?%#[]\" "),
    kCFStringEncodingUTF8));

Использование Core Foundation без ARC:

NSString *escapedString = (NSString *)CFURLCreateStringByAddingPercentEscapes(
    NULL,
   (CFStringRef)unescaped,
    NULL,
    CFSTR("!*'();:@&=+$,/?%#[]\" "),
    kCFStringEncodingUTF8);

Заметка: -stringByAddingPercentEscapesUsingEncoding не будет производить правильную кодировку, в этом случае он не будет кодировать ничего, возвращающее ту же строку.

stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding кодирует 14 символов:

`#% ^ {} [] | \" <> плюс символ пробела в процентах.

testString:

" `~!@#$%^&*()_+-={}[]|\\:;\"'<,>.?/AZaz"  

encodedString:

"%20%60~!@%23$%25%5E&*()_+-=%7B%7D%5B%5D%7C%5C:;%22'%3C,%3E.?/AZaz"  

Примечание: подумайте, соответствует ли этот набор символов вашим потребностям, если не измените их по мере необходимости.

RFC 3986 символов, требующих кодировки (добавлен%, поскольку это символ префикса кодировки):

"! # $ & '() * +, /:; =? @ []%"

Некоторые «незарезервированные символы» дополнительно кодируются:

"\ n \ r \"% -. <> \ ^ _ `{|} ~"

Zaph
источник
1
Также обратите внимание, что вы можете использовать -stringByAddingPercentEscapesUsingEncodingметод NSString .
Майк Веллер,
2
Ах, да, теперь я вспоминаю это странное stringByAddingPercentEscapesUsingEncodingповедение. Он кодирует только '&' и '=' или что-нибудь в этом роде.
Майк Веллер,
2
Согласно RFC1738 вам также потребуется кодировать дополнительные символы. Таким образом, хотя это действительно ответ на вопрос OP, он имеет ограниченную полезность в качестве универсального кодировщика URL. Например, он не обрабатывает не буквенно-цифровые символы, такие как немецкий умляут.
Alex Nauda 05
3
Это не работает (для части iOS 7). Это не преобразует & в% 26.
coolcool1994
1
Создайте нужный набор символов из NSStringwith characterSetWithCharactersInString, возьмите обратное invertedSetи используйте его с stringByAddingPercentEncodingWithAllowedCharacters. Для примера см. Этот SO-ответ .
zaph
23

Это называется кодировкой URL . Подробнее здесь .

-(NSString *)urlEncodeUsingEncoding:(NSStringEncoding)encoding {
    return (NSString *)CFURLCreateStringByAddingPercentEscapes(NULL,
           (CFStringRef)self,
           NULL,
           (CFStringRef)@"!*'\"();:@&=+$,/?%#[]% ",
           CFStringConvertNSStringEncodingToEncoding(encoding));
}
ларсак
источник
3
Это было бы намного полезнее, если бы в ответ был включен какой-то контент из опубликованных вами ссылок.
chown
1
CFURLCreateStringByAddingPercentEscapes()не рекомендуется. [NSString stringByAddingPercentEncodingWithAllowedCharacters:]Вместо этого используйте .
Pang
7

Это не мое решение. Кто-то еще писал в stackoverflow, но я забыл, как это сделать.

Как-то это решение работает "хорошо". Он обрабатывает диакритические знаки, китайские иероглифы и многое другое.

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

Если кто-то скажет мне, кто написал этот код, я буду очень признателен. По сути, у него есть объяснение, почему эта закодированная строка будет декодироваться именно так, как ей хочется.

Я немного изменил его решение. Мне нравится, когда пространство обозначается% 20, а не +. Вот и все.

Анонимный Белый
источник
Исходный код: stackoverflow.com/questions/3423545/…
hsoi
что такое [self UTF8String]?
Yuchao Zhou 01
1
@yuchaozh - это функция, которую вы помещаете в категорию NSString. Итак, self - это NSStirng, а [self UTF8String] возвращает, предположительно, свою строку в формате UTF8.
Келси
4
 NSString * encodedString = (NSString *)CFURLCreateStringByAddingPercentEscapes(NUL,(CFStringRef)@"parameter",NULL,(CFStringRef)@"!*'();@&+$,/?%#[]~=_-.:",kCFStringEncodingUTF8 );

NSURL * url = [[NSURL alloc] initWithString:[@"address here" stringByAppendingFormat:@"?cid=%@",encodedString, nil]];
Захи
источник
1
освободить encodedString и url. этот код касается параметра кодирования. Для кодирования всего адреса передайте строку вместо «параметра».
Захи
Это сработало для меня ... закодировал даже символ &, с которым у меня были проблемы.
Виктор Иванов
3

Это может работать в Objective C ARC. Используйте CFBridgingRelease, чтобы преобразовать объект в стиле Core Foundation как объект Objective-C и передать право собственности на объект ARC. См . Функцию CFBridgingRelease здесь.

+ (NSString *)encodeUrlString:(NSString *)string {
return CFBridgingRelease(CFURLCreateStringByAddingPercentEscapes
                         (kCFAllocatorDefault,
                          (__bridge CFStringRef)string,
                          NULL,
                          CFSTR("!*'();:@&=+$,/?%#[]"),
                          kCFStringEncodingUTF8)
                         );}
Neuneed
источник
2

Swift iOS:

Просто для информации: я использовал это:

extension String {

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

}// end extension String
Винод Джоши
источник
1
NSString *str = (NSString *)CFURLCreateStringByAddingPercentEscapes(
                             NULL,
                             (CFStringRef)yourString, 
                             NULL, 
                             CFSTR("/:"), 
                             kCFStringEncodingUTF8);

Вам нужно будет освободить или автоматически выпустить strсебя.

Wevah
источник
1

Вот что я использую. Обратите внимание, что вы должны использовать@autoreleasepool функцию, иначе программа может вывести из строя или заблокировать IDE. Мне пришлось перезапустить свою IDE три раза, пока я не понял, как исправить. Похоже, что этот код совместим с ARC.

Этот вопрос задавали много раз, и было дано много ответов, но, к сожалению, все выбранные (и несколько других предложенных) неверны.

Вот тестовая строка, которую я использовал: This is my 123+ test & test2. Got it?!

Это мои методы класса Objective C ++:

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
источник
0

Google реализует это в своей панели инструментов Google для Mac . Так что это хорошее место, чтобы увидеть, как они это делают. Другой вариант - включить Toolbox и использовать их реализацию.

Ознакомьтесь с реализацией здесь . (Это сводится к тому, что люди здесь публикуют).

wrtsprt
источник
0

Вот как я делаю это быстро.

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

    func decodeURIComponent() -> String {
        return self.componentsSeparatedByString("+").joinWithSeparator(" ").stringByRemovingPercentEncoding!
    }
}
Андрей
источник
-1

// использовать метод экземпляра NSString следующим образом:

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

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

помните, вы должны кодировать или декодировать только значение вашего параметра, а не весь запрашиваемый URL.

Lingtianlan
источник
2
stringByReplacingPercentEscape usingencoding: только экранирует & и = :-(
Sébastien Stormacq
1
Правильно, поэтому такие вещи, как +, не кодируются, когда они должны быть. Так что не используйте приведенный выше ответ
Джон Баллинджер
-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 );
адер
источник