Pengodean Objective-C dan Swift URL

137

Saya punya yang NSStringseperti ini:

http://www.

tapi saya ingin mengubahnya menjadi:

http%3A%2F%2Fwww.

Bagaimana saya bisa melakukan ini?

Usi Usi
sumber
1
Saya memiliki string terenkripsi seperti ùÕ9y^VêÏÊEØ®.ú/V÷ÅÖêú2Èh~- sepertinya tidak ada solusi di bawah ini yang mengatasi masalah ini!
Mahendra Liya

Jawaban:

324

Untuk menghindari karakter yang Anda inginkan adalah sedikit lebih banyak pekerjaan.

Kode contoh

iOS7 dan di atasnya:

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

Output NSLog:

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

Berikut ini adalah set karakter penyandian URL yang berguna:

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

Membuat rangkaian karakter yang menggabungkan semua hal di atas:

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

Membuat Base64

Dalam kasus Base64 karakter:

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

Untuk Swift 3.0:

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

Untuk Swift 2.x:

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

Catatan: stringByAddingPercentEncodingWithAllowedCharactersjuga akan menyandikan karakter UTF-8 yang membutuhkan penyandian.

Pra iOS7 menggunakan Core Foundation
Menggunakan Core Foundation With ARC:

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

Menggunakan Core Foundation Tanpa ARC:

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

Catatan: -stringByAddingPercentEscapesUsingEncodingtidak akan menghasilkan penyandian yang benar, dalam hal ini tidak akan menyandikan apa pun yang mengembalikan string yang sama.

stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding mengkodekan 14 karakter:

`#% ^ {} [] | \" <> ditambah karakter spasi saat persen lolos.

testString:

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

encodedString:

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

Catatan: pertimbangkan apakah rangkaian karakter ini memenuhi kebutuhan Anda, jika tidak mengubahnya sesuai kebutuhan.

RFC 3986 karakter yang memerlukan pengodean (% ditambahkan karena ini adalah karakter awalan pengodean):

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

Beberapa "karakter yang tidak dilindungi" juga disandikan:

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

zaph
sumber
1
Perhatikan juga Anda dapat menggunakan -stringByAddingPercentEscapesUsingEncodingmetode NSString .
Mike Weller
2
Ah ya, sekarang saya ingat stringByAddingPercentEscapesUsingEncodingperilaku funky . Itu hanya mengkodekan '&' dan '=' atau sesuatu yang konyol seperti itu.
Mike Weller
2
Menurut RFC1738 Anda perlu mengkodekan karakter tambahan juga. Jadi, meskipun ini menjawab pertanyaan OP, kegunaannya terbatas sebagai penyandi URL tujuan umum. Misalnya, itu tidak menangani non-alfanumerik seperti umlaut Jerman.
Alex Nauda
3
Ini tidak berfungsi (untuk iOS 7 bagian). Ini tidak mengonversi & menjadi% 26.
coolcool1994
1
Buat set karakter yang Anda butuhkan dari NSStringdengan characterSetWithCharactersInString, ambil kebalikannya invertedSetdan gunakan dengan stringByAddingPercentEncodingWithAllowedCharacters. Sebagai contoh, lihat jawaban SO ini .
zaph
22

Ini disebut pengkodean URL . Lebih lanjut di sini .

-(NSString *)urlEncodeUsingEncoding:(NSStringEncoding)encoding {
    return (NSString *)CFURLCreateStringByAddingPercentEscapes(NULL,
           (CFStringRef)self,
           NULL,
           (CFStringRef)@"!*'\"();:@&=+$,/?%#[]% ",
           CFStringConvertNSStringEncodingToEncoding(encoding));
}
larsacus
sumber
3
Ini akan jauh lebih berguna jika beberapa konten dari tautan yang Anda posting dimasukkan dalam jawaban.
chown
1
CFURLCreateStringByAddingPercentEscapes()sudah ditinggalkan. Gunakan [NSString stringByAddingPercentEncodingWithAllowedCharacters:]sebagai gantinya.
Pang
7

Ini bukan solusi saya. Orang lain menulis di stackoverflow tetapi saya lupa caranya.

Entah bagaimana solusi ini bekerja "dengan baik". Ini menangani diakritik, karakter Cina, dan hampir semua hal lainnya.

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

Jika seseorang memberi tahu saya siapa yang menulis kode ini, saya akan sangat menghargainya. Pada dasarnya ia memiliki beberapa penjelasan mengapa string yang dikodekan ini akan memecahkan kode persis seperti yang diinginkan.

Saya memodifikasi solusinya sedikit. Saya suka ruang diwakili dengan% 20 daripada +. Itu saja.

Putih Anonim
sumber
apa itu [self UTF8String]?
Yuchao Zhou
1
@yuchaozh ini adalah fungsi yang Anda masukkan ke dalam kategori NSString. Jadi, self adalah NSStirng dan [self UTF8String] mengembalikan, dengan asumsi, stringnya dalam format 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
sumber
1
lepaskan encodedString dan url. kode ini adalah tentang parameter penyandian. Untuk menyandikan seluruh string pass alamat alih-alih "parameter".
Zahi
Ini bekerja untuk saya ... disandikan bahkan karakter & yang saya mengalami masalah dengan.
Виктор Иванов
3

Ini dapat bekerja di Objective C ARC. Gunakan CFBridgingRelease untuk melemparkan objek gaya Core Foundation sebagai objek Objective-C dan mentransfer kepemilikan objek ke ARC. Lihat Fungsi CFBridgingRelease di sini.

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

IOS Swift:

Sekadar Informasi: Saya telah menggunakan ini:

extension String {

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

}// end extension String
Vinod Joshi
sumber
1
NSString *str = (NSString *)CFURLCreateStringByAddingPercentEscapes(
                             NULL,
                             (CFStringRef)yourString, 
                             NULL, 
                             CFSTR("/:"), 
                             kCFStringEncodingUTF8);

Anda perlu melepaskan atau melepaskan strsendiri.

Wevah
sumber
1

Inilah yang saya gunakan. Catatan Anda harus menggunakan @autoreleasepoolfitur ini atau program mungkin crash atau mengunci IDE. Saya harus me-restart IDE saya tiga kali sampai saya menyadari perbaikannya. Tampaknya kode ini sesuai dengan ARC.

Pertanyaan ini telah ditanyakan berkali-kali, dan banyak jawaban diberikan, tetapi sayangnya semua jawaban yang dipilih (dan beberapa lainnya menyarankan) salah.

Inilah string tes yang saya gunakan: This is my 123+ test & test2. Got it?!

Ini adalah metode kelas Objective C ++ saya:

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
sumber
0

Google mengimplementasikan ini di Google Toolbox untuk Mac mereka . Jadi itu adalah tempat yang bagus untuk memuncak bagaimana mereka melakukannya. Pilihan lain adalah memasukkan Toolbox dan menggunakan implementasinya.

Lihat implementasinya di sini . (Yang turun persis seperti apa yang orang posting di sini).

wrtsprt
sumber
0

Ini adalah bagaimana saya melakukan ini dengan cepat.

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

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

// gunakan metode instance NSString seperti ini:

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

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

ingat, Anda hanya harus melakukan encode atau decode untuk nilai parameter Anda, tidak semua url yang Anda minta.

lingtianlan
sumber
2
stringByReplacingPercentEscapeusingencoding: hanya lolos & dan = :-(
Sébastien Stormacq
1
Benar, sehingga hal-hal seperti + tidak disandikan, ketika perlu +. Jadi jangan gunakan jawaban di atas
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
sumber