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ć?


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


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

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.



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

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

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

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

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


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


0

Oto jak robię to szybko.

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

    func decodeURIComponent() -> String {
        return self.componentsSeparatedByString("+").joinWithSeparator(" ").stringByRemovingPercentEncoding!
    }
}

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


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 );
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.