Bagaimana cara URL menyandikan string

Jawaban:

291

Sayangnya, stringByAddingPercentEscapesUsingEncodingtidak selalu berhasil 100%. Ini mengkodekan karakter non-URL tetapi meninggalkan karakter yang dipesan (seperti slash /dan ampersand &) sendirian. Rupanya ini adalah bug yang diketahui Apple, tetapi karena mereka belum memperbaikinya, saya telah menggunakan kategori ini untuk meng-url-encode sebuah string:

@implementation NSString (NSString_Extended)

- (NSString *)urlencode {
    NSMutableString *output = [NSMutableString string];
    const unsigned char *source = (const unsigned char *)[self UTF8String];
    int sourceLen = strlen((const char *)source);
    for (int i = 0; i < sourceLen; ++i) {
        const unsigned char thisChar = source[i];
        if (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;
}

Digunakan seperti ini:

NSString *urlEncodedString = [@"SOME_URL_GOES_HERE" urlencode];

// Or, with an already existing string:
NSString *someUrlString = @"someURL";
NSString *encodedUrlStr = [someUrlString urlencode];

Ini juga berfungsi:

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

Beberapa bacaan yang bagus tentang subjek:

Objektif-c iPhone persen menyandikan string?
Pengodean Objective-C dan Swift URL

http://cybersam.com/programming/proper-url-percent-encoding-in-ios
https://devforums.apple.com/message/15674#15674 http://simonwoodside.com/weblog/2009/4/ 22 / how_to_really_url_encode /

dikunyah
sumber
12
Mengapa Anda menggunakan kategori yang rumit seperti ini daripada hanya menjatuhkannya ke CFURLCreateStringByAddingPercentEscapes () , di mana Anda dapat secara eksplisit menentukan karakter yang ingin selalu Anda hindari.
Lily Ballard
8
@KevinBallard karena fungsi CF bekerja pada model inklusif ("melarikan diri karakter ini"), dan biasanya Anda ingin bekerja pada model eksklusif ("melarikan diri semua kecuali karakter ini")
Dave DeLong
31
@DaveDeLong Mungkin itu yang saya dapatkan. Ini merupakan kategori standar di semua proyek saya selama kurang lebih satu tahun, jadi saya kira Anda mungkin sumber aslinya! Saya telah mengedit kata-katanya sehingga sepertinya saya tidak mencoba mengambil kredit untuk menulisnya).
chown
4
Mengapa? if (thisChar == '') {[output appendString: @ "+"]; } Tanpa ini jika akan menyandikan spasi dengan% 20 seperti yang saya harapkan
Chris Stephens
127

Ini mungkin bermanfaat

NSString *sampleUrl = @"http://www.google.com/search.jsp?params=Java Developer";
NSString* encodedUrl = [sampleUrl stringByAddingPercentEscapesUsingEncoding:
 NSUTF8StringEncoding];

Untuk iOS 7+, cara yang disarankan adalah:

NSString* encodedUrl = [sampleUrl stringByAddingPercentEncodingWithAllowedCharacters:[NSCharacterSet URLQueryAllowedCharacterSet]];

Anda dapat memilih set karakter yang diizinkan sesuai persyaratan komponen URL.

Nishant
sumber
7
Ini juga tidak menyandikan pembatas parameter dengan benar seperti '&', '?' dalam kasus di mana Anda mengirimkan konten ke API.
Ben Lachman
'&' bukan karakter yang valid untuk parameter string kueri URL. Coba gunakan '& amp;' sebagai gantinya.
Nishant
1
stringByAddingPercentEscapesUsingEncoding DEPRECATED " -stringByAddingPercentEncodingWithAllowedCharacters:Sebagai gantinya, gunakan yang selalu menggunakan pengkodean UTF-8 yang direkomendasikan, dan yang mengkodekan untuk komponen URL tertentu atau subkomponen karena setiap komponen URL atau subkomponen memiliki aturan yang berbeda untuk karakter apa yang valid."
Mihir Oza
89

API baru telah ditambahkan sejak jawaban dipilih; Anda sekarang dapat menggunakan NSURLUtilities. Karena berbagai bagian URL memungkinkan karakter yang berbeda, gunakan rangkaian karakter yang berlaku. Contoh berikut ini dikodekan untuk dimasukkan dalam string kueri:

encodedString = [myString stringByAddingPercentEncodingWithAllowedCharacters:NSCharacterSet.URLQueryAllowedCharacterSet];

Untuk secara khusus mengonversi '&', Anda harus menghapusnya dari set kueri url atau menggunakan set lain, karena '&' diizinkan dalam kueri URL:

NSMutableCharacterSet *chars = NSCharacterSet.URLQueryAllowedCharacterSet.mutableCopy;
[chars removeCharactersInRange:NSMakeRange('&', 1)]; // %26
encodedString = [myString stringByAddingPercentEncodingWithAllowedCharacters:chars];
Peter DeWeese
sumber
1
Butuh beberapa saat untuk mencari tahu apa yang Anda maksud dengan "gunakan NSURLUtilities" - tetapi sekarang saya melihat bahwa itulah nama kategori NSString di mana Apple mendefinisikan metode baru ini di iOS 7 dan OS X 10.9.
Richard Venable
1
Ada jawaban yang lebih terperinci seperti ini di sini: stackoverflow.com/a/20271177/456366
Richard Venable
Ya. Itu juga terdaftar sebagai NSURLUtilities dalam daftar API baru yang dirilis.
Peter DeWeese
Tentu saja '&' diizinkan dalam string kueri, jadi saya akan mengedit jawaban saya menggunakan tautan Richard.
Peter DeWeese
3
NSMakeRange('&', 1)tidak berfungsi di Swift, karena Swift tidak mengizinkan konversi char ke int tanpa peretasan. Untuk menggunakan solusi ini dalam kode Swift, gunakan removeCharactersInString("&")sebagai ganti.removeCharactersInRange(...)
cbh2000
16

Contoh Swift 2.0 (iOS 9 Compatiable)

extension String {

  func stringByURLEncoding() -> String? {

    let characters = NSCharacterSet.URLQueryAllowedCharacterSet().mutableCopy() as! NSMutableCharacterSet

    characters.removeCharactersInString("&")

    guard let encodedString = self.stringByAddingPercentEncodingWithAllowedCharacters(characters) else {
      return nil
    }

    return encodedString

  }

}
Oliver Atkinson
sumber
2
@AlecThomas Anda tampaknya harus melompati beberapa rintangan untuk sampai ke sini, itu sebabnya lebih baik menyembunyikannya dalam ekstensi
Oliver Atkinson
@OliverAtkinson - bagi saya Int (String (Character ("&"))) mengembalikan nihil, sebagaimana mestinya. Alih-alih characters.removeCharactersInString ("&").
ambientlight
14

pembaruan ios 7

NSString *encode = [string stringByAddingPercentEncodingWithAllowedCharacters:[NSCharacterSet URLQueryAllowedCharacterSet]];

NSString *decode = [encode stringByReplacingPercentEscapesUsingEncoding:NSUTF8StringEncoding];
Underdog
sumber
Ini tidak akurat. Anda ingin keluar dari bagian URL yang berbeda secara berbeda. stackoverflow.com/questions/3423545/…
Steve Moser
Ini sebenarnya tergantung pada server Anda untuk karakter yang diperbolehkan, di sini, pada contoh saya di server saya menggunakannya hanya diizinkan set karakter alfanumerik, Anda dapat mengubahnya ke karakter tertentu untuk memenuhi kebutuhan Anda.
Underdog
1
Pertanyaannya adalah tentang penyandian karakter '&'.
Steve Moser
8

Saya memilih untuk menggunakan CFURLCreateStringByAddingPercentEscapespanggilan seperti yang diberikan oleh jawaban yang diterima, namun dalam versi terbaru XCode (dan iOS), itu menghasilkan kesalahan, jadi gunakan yang berikut sebagai gantinya:

NSString *apiKeyRaw = @"79b|7Qd.jW=])(fv|M&W0O|3CENnrbNh4}2E|-)J*BCjCMrWy%dSfGs#A6N38Fo~";

NSString *apiKey = (NSString *)CFBridgingRelease(CFURLCreateStringByAddingPercentEscapes(NULL, (CFStringRef)apiKeyRaw, NULL, (CFStringRef)@"!*'();:@&=+$,/?%#[]", kCFStringEncodingUTF8));
Mike Purcell
sumber
Ini bukan ruang encoding. Contoh @ "string string" dan @ "string & string" dikodekan dengan benar. Tolong beri tahu saya masukan Anda sama.
Yogesh Lolusare
2
bagi saya sebagian besar waktu yang dihabiskan untuk menyelesaikan ini adalah periode penolakan di mana saya menolak untuk percaya kerangka kerja tidak mengandung sesuatu yang bernama mirip dengan 'urlencode' yang melakukan ini tanpa main-main ..
dancl
6

Cobalah menggunakan stringByAddingPercentEncodingWithAllowedCharactersmetode dengan [NSCharacterSet URLUserAllowedCharacterSet]itu akan mencakup semua kasus

Tujuan C

NSString *value = @"Test / Test";
value = [value stringByAddingPercentEncodingWithAllowedCharacters:[NSCharacterSet URLUserAllowedCharacterSet]];

cepat

var value = "Test / Test"
value.stringByAddingPercentEncodingWithAllowedCharacters(NSCharacterSet.URLUserAllowedCharacterSet())

Keluaran

Test%20%2F%20Test

Alex
sumber
6

Setelah membaca semua jawaban untuk topik ini dan yang ( salah ) diterima, saya ingin menambahkan kontribusi saya.

JIKA targetnya adalah iOS7 +, dan pada 2017 semestinya sejak XCode membuat sangat sulit untuk memberikan kompatibilitas di bawah iOS8, cara terbaik, aman thread, cepat, dan akan dukungan penuh UTF-8 untuk melakukan ini adalah:

(Kode C tujuan)

@implementation NSString (NSString_urlencoding)

- (NSString *)urlencode {
    static NSMutableCharacterSet *chars = nil;
    static dispatch_once_t pred;

    if (chars)
        return [self stringByAddingPercentEncodingWithAllowedCharacters:chars];

    // to be thread safe
    dispatch_once(&pred, ^{
        chars = NSCharacterSet.URLQueryAllowedCharacterSet.mutableCopy;
        [chars removeCharactersInString:@"!*'();:@&=+$,/?%#[]"];
    });
    return [self stringByAddingPercentEncodingWithAllowedCharacters:chars];
}
@end

Ini akan memperluas NSString, akan mengecualikan karakter terlarang RFC, mendukung karakter UTF-8, dan membiarkan Anda menggunakan hal-hal seperti:

NSString *myusername = "I'm[evil]&want(to)break!!!$->àéìòù";
NSLog(@"Source: %@ -> Dest: %@", myusername, [myusername urlencode]);

Itu akan dicetak pada konsol debug Anda:

Sumber: Saya [jahat] & ingin istirahat !!! $ -> àéìòù -> Dest: I% 27m% 5Bevil% 5D% 26ingin% 28ke% 29break% 21% 21% 21% 24-% 3E% C3 % A0% C3% A9% C3% AC% C3% B2% C3% B9

... perhatikan juga penggunaan dispatch_once untuk menghindari beberapa inisialisasi dalam lingkungan multithread.

omong kosong
sumber
5

Berikut ini adalah pendekatan fleksibel siap-produksi di Swift 5.x :

public extension CharacterSet {

    static let urlQueryParameterAllowed = CharacterSet.urlQueryAllowed.subtracting(CharacterSet(charactersIn: "&?"))

    static let urlQueryDenied           = CharacterSet.urlQueryAllowed.inverted()
    static let urlQueryKeyValueDenied   = CharacterSet.urlQueryParameterAllowed.inverted()
    static let urlPathDenied            = CharacterSet.urlPathAllowed.inverted()
    static let urlFragmentDenied        = CharacterSet.urlFragmentAllowed.inverted()
    static let urlHostDenied            = CharacterSet.urlHostAllowed.inverted()

    static let urlDenied                = CharacterSet.urlQueryDenied
        .union(.urlQueryKeyValueDenied)
        .union(.urlPathDenied)
        .union(.urlFragmentDenied)
        .union(.urlHostDenied)


    func inverted() -> CharacterSet {
        var copy = self
        copy.invert()
        return copy
    }
}



public extension String {
    func urlEncoded(denying deniedCharacters: CharacterSet = .urlDenied) -> String? {
        return addingPercentEncoding(withAllowedCharacters: deniedCharacters.inverted())
    }
}

Contoh penggunaan:

print("Hello, World!".urlEncoded()!)
print("You&Me?".urlEncoded()!)
print("#Blessed 100%".urlEncoded()!)
print("Pride and Prejudice".urlEncoded(denying: .uppercaseLetters)!)

Keluaran:

Hello,%20World!
You%26Me%3F
%23Blessed%20100%25
%50ride and %50rejudice
Ben Leggiero
sumber
Harap sertakan komentar yang menjelaskan alasan downvotes Anda, jadi saya tahu bagaimana menulis jawaban yang lebih baik di masa mendatang 🙂
Ben Leggiero
4

Gunakan komponen NSURLC untuk mengkodekan parameter GET HTTP:

    var urlComponents = NSURLComponents(string: "https://www.google.de/maps/")!
    urlComponents.queryItems = [
        NSURLQueryItem(name: "q", value: String(51.500833)+","+String(-0.141944)),
        NSURLQueryItem(name: "z", value: String(6))
    ]
    urlComponents.URL     // returns https://www.google.de/maps/?q=51.500833,-0.141944&z=6

http://www.ralfebert.de/snippets/ios/encoding-nsurl-get-parameters/

Ralf Ebert
sumber
1
Itu tidak menyandikan ampersand, garis miring atau titik koma.
Fábio Oliveira
4

Kode ini membantu saya untuk penyandian karakter khusus

NSString* encPassword = [password stringByAddingPercentEncodingWithAllowedCharacters:[NSCharacterSet alphanumericCharacterSet]];
Rupesh Baldania
sumber
3

kode cepat berdasarkan jawaban objek chown di utas ini.

extension String {
    func urlEncode() -> String {
        return CFURLCreateStringByAddingPercentEscapes(
            nil,
            self,
            nil,
            "!*'();:@&=+$,/?%#[]",
            CFStringBuiltInEncodings.UTF8.rawValue
        )
    }
}
neoneye
sumber
4
fungsi ini sudah tidak digunakan lagi di iOS 9 :(
Oliver Atkinson
3

Di Swift 3 , silakan coba di bawah ini:

let stringURL = "YOUR URL TO BE ENCODE";
let encodedURLString = stringURL.addingPercentEncoding(withAllowedCharacters: .urlHostAllowed)
print(encodedURLString)

Karena, stringByAddingPercentEscapesUsingEncodingmenyandikan karakter bukan URL tetapi meninggalkan karakter yang dipesan (seperti !*'();:@&=+$,/?%#[]), Anda dapat menyandikan url seperti kode berikut:

let stringURL = "YOUR URL TO BE ENCODE";
let characterSetTobeAllowed = (CharacterSet(charactersIn: "!*'();:@&=+$,/?%#[] ").inverted)
if let encodedURLString = stringURL.addingPercentEncoding(withAllowedCharacters: characterSetTobeAllowed) {
    print(encodedURLString)
}
Dinesh
sumber
2

Dalam cepat 3:

// exclude alpha and numeric == "full" encoding
stringUrl = stringUrl.addingPercentEncoding(withAllowedCharacters: .alphanumerics)!;

// exclude hostname and symbols &,/ and etc
stringUrl = stringUrl.addingPercentEncoding(withAllowedCharacters: .urlHostAllowed)!;
laut-kg
sumber
2

Saran Apple, dalam catatan rilis 10.11, adalah:

Jika Anda perlu meng-enkode seluruh string URL, Anda dapat menggunakan kode ini untuk menyandikan NSString yang dimaksudkan sebagai URL (dalam urlStringToEncode):

NSString *percentEncodedURLString =
  [[NSURL URLWithDataRepresentation:[urlStringToEncode dataUsingEncoding:NSUTF8StringEncoding] relativeToURL:nil] relativeString];
nithinbhaktha
sumber
sepertinya tidak berfungsi, karakter seperti & masih dibiarkan sendiri
kjyv
1

Dalam kasus saya di mana komponen terakhir adalah huruf Arab yang saya lakukan berikut di Swift 2.2:

extension String {

 func encodeUTF8() -> String? {

    //If I can create an NSURL out of the string nothing is wrong with it
    if let _ = NSURL(string: self) {

        return self
    }

    //Get the last component from the string this will return subSequence
    let optionalLastComponent = self.characters.split { $0 == "/" }.last


    if let lastComponent = optionalLastComponent {

        //Get the string from the sub sequence by mapping the characters to [String] then reduce the array to String
        let lastComponentAsString = lastComponent.map { String($0) }.reduce("", combine: +)


        //Get the range of the last component
        if let rangeOfLastComponent = self.rangeOfString(lastComponentAsString) {
            //Get the string without its last component
            let stringWithoutLastComponent = self.substringToIndex(rangeOfLastComponent.startIndex)


            //Encode the last component
            if let lastComponentEncoded = lastComponentAsString.stringByAddingPercentEncodingWithAllowedCharacters(NSCharacterSet.alphanumericCharacterSet()) {


            //Finally append the original string (without its last component) to the encoded part (encoded last component)
            let encodedString = stringWithoutLastComponent + lastComponentEncoded

                //Return the string (original string/encoded string)
                return encodedString
            }
        }
    }

    return nil;
}
}

pemakaian:

let stringURL = "http://xxx.dev.com/endpoint/nonLatinCharacters"

if let encodedStringURL = stringURL.encodeUTF8() {

    if let url = NSURL(string: encodedStringURL) {

      ...
    }

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

menurut blog berikut

Anton Kashpor
sumber
Tetapi sudah tidak digunakan lagi di iOS 9. Apa kode yang diperbarui untuk ini?
Sujit Nachan
1

Begitu banyak jawaban tetapi tidak berhasil untuk saya, jadi saya mencoba yang berikut:

fun simpleServiceCall(for serviceUrl: String, appendToUrl: String) { 
    let urlString: String = serviceUrl + appendToUrl.addingPercentEncoding(withAllowedCharacters: .urlPathAllowed)!     

    let finalUrl = URL(string: urlString)!

    //continue to execute your service call... 
}

Semoga itu bisa membantu seseorang. Terima kasih

Sanjeevcn
sumber
0

Untuk parameter kueri yang di-encode formulir www, saya membuat kategori di NSString:

- (NSString*)WWWFormEncoded{
     NSMutableCharacterSet *chars = NSCharacterSet.alphanumericCharacterSet.mutableCopy;
     [chars addCharactersInString:@" "];
     NSString* encodedString = [self stringByAddingPercentEncodingWithAllowedCharacters:chars];
     encodedString = [encodedString stringByReplacingOccurrencesOfString:@" " withString:@"+"];
     return encodedString;
}
Pete Kamm
sumber
0

// Ini tanpa ujian

NSMutableCharacterSet* set = [[NSCharacterSet alphanumericCharacterSet] mutableCopy];
[set addCharactersInString:@"-_.~"];
NSString *encode = [test stringByAddingPercentEncodingWithAllowedCharacters:set];
Achilles Wang
sumber
0

Saya menghadapi masalah serupa melewati string kompleks sebagai parameter POST. String saya dapat berisi karakter Asia, spasi, kutipan, dan segala macam karakter khusus. Solusi yang akhirnya saya temukan adalah mengubah string saya menjadi seri unicodes yang cocok, misalnya "Hu0040Hu0020Hu03f5 ...." menggunakan [NSString stringWithFormat: @ "Hu% 04x", [string characterAtIndex: i]] untuk mendapatkan Unicode dari masing-masing karakter dalam string asli. Hal yang sama dapat dilakukan di Jawa.

String ini dapat dengan aman diteruskan sebagai parameter POST.

Di sisi server (PHP), saya mengubah semua "H" menjadi "\" dan saya meneruskan string yang dihasilkan ke json_decode. Langkah terakhir adalah menghindari tanda kutip tunggal sebelum menyimpan string ke dalam MySQL.

Dengan cara ini saya dapat menyimpan string UTF8 di server saya.

Georges
sumber
0

Yang ini bekerja untuk saya.

func stringByAddingPercentEncodingForFormData(plusForSpace: Bool=false) -> String? {
    let unreserved = "*-._"
    let allowed = NSMutableCharacterSet.alphanumericCharacterSet()
    allowed.addCharactersInString(unreserved)

    if plusForSpace {
        allowed.addCharactersInString(" ")
    }

    var encoded = stringByAddingPercentEncodingWithAllowedCharacters(allowed)
    if plusForSpace {
        encoded = encoded?.stringByReplacingOccurrencesOfString(" ",
                                                                withString: "+")
    }
    return encoded
}

Saya menemukan fungsi di atas dari tautan ini: http://useyourloaf.com/blog/how-to-percent-encode-a-url-string/

Anda juga dapat menggunakan fungsi ini dengan ekstensi cepat. Tolong beri tahu saya jika ada masalah.

Gaurav Singla
sumber