Kodowanie Objective-C i Swift URL

137

Mam NSStringtaki:

http://www.

ale chcę to przekształcić w:

http%3A%2F%2Fwww.

W jaki sposób mogę to zrobić?

Usi Usi
źródło
1
Mam zaszyfrowany ciąg znaków ùÕ9y^VêÏÊEØ®.ú/V÷ÅÖêú2Èh~- żadne z poniższych rozwiązań nie wydaje się rozwiązać tego problemu!
Mahendra Liya

Odpowiedzi:

324

Ucieczka przed postaciami, które chcesz, to trochę więcej pracy.

Przykładowy kod

iOS7 i nowsze:

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

Wyjście NSLog:

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

Poniżej przedstawiono przydatne zestawy znaków do kodowania adresów URL:

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

Tworzenie zestawu znaków łączącego wszystkie powyższe:

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

Tworzenie Base64

W przypadku zestawu znaków Base64:

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

Dla Swift 3.0:

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

Dla Swift 2.x:

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

Uwaga: stringByAddingPercentEncodingWithAllowedCharacterszakoduje również znaki UTF-8 wymagające kodowania.

Przed iOS7 używaj Core Foundation
przy użyciu Core Foundation z ARC:

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

Korzystanie z Core Foundation bez ARC:

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

Uwaga: -stringByAddingPercentEscapesUsingEncodingnie wygeneruje prawidłowego kodowania, w tym przypadku nie zakoduje niczego zwracającego ten sam ciąg.

stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding koduje 14 znaków:

`#% ^ {} [] | \" <> plus znak spacji jako procent ucieczki.

testString:

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

encodedString:

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

Uwaga: zastanów się, czy ten zestaw znaków spełnia Twoje potrzeby, jeśli nie, zmień je w razie potrzeby.

Znaki RFC 3986 wymagające kodowania (% dodane, ponieważ jest to znak prefiksu kodowania):

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

Niektóre „niezarezerwowane znaki” są dodatkowo zakodowane:

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

uff
źródło
1
Zauważ również, że możesz użyć -stringByAddingPercentEscapesUsingEncodingmetody NSString .
Mike Weller
2
Ach tak, teraz pamiętam dziwne stringByAddingPercentEscapesUsingEncodingzachowanie. Koduje tylko „&” i „=” lub coś takiego niedorzecznego.
Mike Weller
2
Zgodnie z RFC1738 musiałbyś również zakodować dodatkowe znaki. Więc chociaż to odpowiada na pytanie OP, ma ograniczoną użyteczność jako koder URL ogólnego przeznaczenia. Na przykład nie obsługuje znaków innych niż alfanumeryczne, takich jak niemiecki umlaut.
Alex Nauda,
3
To nie działa (dla części iOS 7). To nie konwertuje & na% 26.
coolcool1994
1
Utwórz zestaw znaków, którego potrzebujesz z NSStringwith characterSetWithCharactersInString, weź odwrotność z invertedSeti użyj tego z stringByAddingPercentEncodingWithAllowedCharacters. Na przykład zobacz tę odpowiedź SO .
zaph
22

Nazywa się to kodowaniem adresów URL . Więcej tutaj .

-(NSString *)urlEncodeUsingEncoding:(NSStringEncoding)encoding {
    return (NSString *)CFURLCreateStringByAddingPercentEscapes(NULL,
           (CFStringRef)self,
           NULL,
           (CFStringRef)@"!*'\"();:@&=+$,/?%#[]% ",
           CFStringConvertNSStringEncodingToEncoding(encoding));
}
larsacus
źródło
3
Byłoby to o wiele bardziej przydatne, gdyby w odpowiedzi uwzględniono treść z opublikowanych przez Ciebie linków.
chown
1
CFURLCreateStringByAddingPercentEscapes()jest przestarzałe. Użyj [NSString stringByAddingPercentEncodingWithAllowedCharacters:]zamiast tego.
Pang
7

To nie jest moje rozwiązanie. Ktoś inny napisał w stackoverflow, ale zapomniałem jak.

Jakoś to rozwiązanie działa „dobrze”. Obsługuje znaki diakrytyczne, chińskie i prawie wszystko inne.

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

Gdyby ktoś mi powiedział, kto napisał ten kod, będę bardzo wdzięczny. Zasadniczo ma pewne wyjaśnienie, dlaczego ten zakodowany ciąg będzie dekodował dokładnie tak, jak sobie życzy.

Zmodyfikowałem trochę jego rozwiązanie. Wolę, aby przestrzeń była reprezentowana za pomocą% 20 zamiast +. To wszystko.

Anonimowy biały
źródło
co to jest [własny ciąg UTF8String]?
Yuchao Zhou
1
@yuchaozh to jest funkcja, którą umieszczasz w kategorii NSString. Tak więc self to NSStirng i [self UTF8String] zwraca, zakładając, swój ciąg w formacie UTF8.
Kelsey
4
 NSString * encodedString = (NSString *)CFURLCreateStringByAddingPercentEscapes(NUL,(CFStringRef)@"parameter",NULL,(CFStringRef)@"!*'();@&+$,/?%#[]~=_-.:",kCFStringEncodingUTF8 );

NSURL * url = [[NSURL alloc] initWithString:[@"address here" stringByAppendingFormat:@"?cid=%@",encodedString, nil]];
Zahi
źródło
1
release encodedString i url. ten kod dotyczy parametru kodowania. Aby zakodować cały ciąg adresu zamiast „parametru”.
Zahi
To zadziałało dla mnie ... zakodował nawet znak &, z którym miałem problemy.
Виктор Иванов
3

Może to działać w ARC Objective C. Użyj CFBridgingRelease, aby rzutować obiekt w stylu Core Foundation jako obiekt Objective-C i przenieść własność obiektu na ARC .Patrz Funkcja CFBridgingRelease tutaj.

+ (NSString *)encodeUrlString:(NSString *)string {
return CFBridgingRelease(CFURLCreateStringByAddingPercentEscapes
                         (kCFAllocatorDefault,
                          (__bridge CFStringRef)string,
                          NULL,
                          CFSTR("!*'();:@&=+$,/?%#[]"),
                          kCFStringEncodingUTF8)
                         );}
Neuneed
źródło
2

Swift iOS:

Tylko dla informacji: użyłem tego:

extension String {

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

}// end extension String
Vinod Joshi
źródło
1
NSString *str = (NSString *)CFURLCreateStringByAddingPercentEscapes(
                             NULL,
                             (CFStringRef)yourString, 
                             NULL, 
                             CFSTR("/:"), 
                             kCFStringEncodingUTF8);

Będziesz musiał zwolnić lub automatycznie strsię zwolnić .

Wevah
źródło
1

Oto czego używam. Pamiętaj, że musisz użyć@autoreleasepool funkcji lub program może zawiesić lub zablokować IDE. Musiałem trzykrotnie zrestartować IDE, zanim zdałem sobie sprawę z poprawki. Wygląda na to, że ten kod jest zgodny z ARC.

To pytanie było zadawane wiele razy i udzielono wielu odpowiedzi, ale niestety wszystkie wybrane (i kilka innych sugerowanych) są błędne.

Oto ciąg testowy, którego użyłem: This is my 123+ test & test2. Got it?!

Oto moje metody klasy 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
źródło
0

Google implementuje to w swoim programie Google Toolbox dla komputerów Mac . To dobre miejsce, aby zobaczyć, jak to robią. Inną opcją jest dołączenie Toolbox i użycie ich implementacji.

Sprawdź implementację tutaj . (Co sprowadza się dokładnie do tego, co ludzie tutaj publikowali).

wrtsprt
źródło
0

Oto jak robię to szybko.

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

    func decodeURIComponent() -> String {
        return self.componentsSeparatedByString("+").joinWithSeparator(" ").stringByRemovingPercentEncoding!
    }
}
Andy
źródło
-1

// użyj metody instancji NSString w następujący sposób:

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

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

pamiętaj, że powinieneś kodować lub dekodować tylko wartość parametru, a nie cały adres URL, o który prosisz.

lingtianlan
źródło
2
stringByReplacingPercentEscapeusingencoding: only escapes & and = :-(
Sébastien Stormacq
1
Prawidłowo, więc rzeczy takie jak + nie są kodowane, kiedy trzeba. Więc nie używaj powyższej odpowiedzi
John Ballinger
-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
źródło