Come posso codificare l'URL di una stringa


Risposte:


291

Sfortunatamente, stringByAddingPercentEscapesUsingEncodingnon funziona sempre al 100%. Codifica caratteri non URL ma lascia da soli i caratteri riservati (come barra /e commerciale &). Apparentemente questo è un bug di cui Apple è a conoscenza, ma dal momento che non l'hanno ancora risolto, sto usando questa categoria per url-codificare una stringa:

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

Usato così:

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

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

Questo funziona anche:

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

Qualche buona lettura sull'argomento:

La percentuale di iPhone Objective-c codifica una stringa?
Codifica Objective-C e 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 /


12
Perché mai dovresti usare una categoria complicata come questa invece di scendere a CFURLCreateStringByAddingPercentEscapes () , dove puoi specificare esplicitamente a quali caratteri vuoi sempre scappare.
Lily Ballard,

8
@KevinBallard perché la funzione CF funziona su un modello inclusivo ("sfuggire a questi personaggi"), e di solito vuoi lavorare su un modello esclusivo ("sfuggire a tutto tranne questi personaggi")
Dave DeLong,


31
@DaveDeLong Questo potrebbe essere dove l'ho preso. È stata una categoria standard in tutti i miei progetti per circa un anno, quindi immagino che tu possa essere stata la fonte originale! Ho modificato il testo in modo che non sembri cercare di prendermi il merito per averlo scritto).
vestito l'

4
Perché? if (thisChar == '') {[output appendString: @ "+"]; } Senza questo se codificherà gli spazi con% 20 come mi sarei aspettato
Chris Stephens

127

Questo potrebbe essere utile

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

Per iOS 7+, il modo consigliato è:

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

È possibile scegliere il set di caratteri consentito in base ai requisiti del componente URL.


7
Anche questo non codifica correttamente i delimitatori di parametri come '&', '?' nel caso in cui si stia passando contenuto in un'API.
Ben Lachman,

'&' non è un carattere valido per il parametro della stringa di query URL. Prova a utilizzare "& amp;" anziché.
Nishant,

1
stringByAddingPercentEscapesUsingEncoding è DEPRECATED "Usa -stringByAddingPercentEncodingWithAllowedCharacters:invece, che utilizza sempre la codifica UTF-8 consigliata e che codifica per un componente o sottocomponente URL specifico poiché ciascun componente o sottocomponente URL ha regole diverse per quali caratteri sono validi."
Mihir Oza,

89

Sono state aggiunte nuove API da quando è stata selezionata la risposta; Ora puoi usare NSURLUtilities. Poiché parti diverse di URL consentono caratteri diversi, utilizzare il set di caratteri applicabile. L'esempio seguente codifica per l'inclusione nella stringa di query:

encodedString = [myString stringByAddingPercentEncodingWithAllowedCharacters:NSCharacterSet.URLQueryAllowedCharacterSet];

Per convertire specificamente "&", devi rimuoverlo dal set di query dell'URL o utilizzare un set diverso, poiché "&" è consentito in una query URL:

NSMutableCharacterSet *chars = NSCharacterSet.URLQueryAllowedCharacterSet.mutableCopy;
[chars removeCharactersInRange:NSMakeRange('&', 1)]; // %26
encodedString = [myString stringByAddingPercentEncodingWithAllowedCharacters:chars];

1
Mi ci è voluto un po 'di tempo per capire cosa intendevi per "usare NSURLUtilities" - ma ora vedo che quello è il nome della categoria di NSString in cui Apple ha definito questo nuovo metodo in iOS 7 e OS X 10.9.
Richard Venable,

1
C'è una risposta più elaborata come questa qui: stackoverflow.com/a/20271177/456366
Richard Venable

Sì. È stato anche elencato come NSURLUtilities nell'elenco delle nuove API rilasciate.
Peter DeWeese,

"&" è ovviamente consentito in una stringa di query, quindi modificherò la mia risposta usando il link di Richard.
Peter DeWeese,

3
NSMakeRange('&', 1)non funziona in Swift, perché Swift non consente la conversione int di char senza hack. Per utilizzare questa soluzione nel codice Swift, utilizzare removeCharactersInString("&")invece di.removeCharactersInRange(...)
cbh2000 il

16

Esempio Swift 2.0 (iOS 9 compatibile)

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

  }

}

2
@AlecThomas sembra che tu debba saltare attraverso alcuni cerchi per arrivare qui, ecco perché è meglio nasconderlo in un'estensione
Oliver Atkinson,

@OliverAtkinson - per me Int (String (Character ("&"))) restituisce zero, come dovrebbe. Invece characters.removeCharactersInString ("&").
ambientlight

14

aggiornamento iOS 7

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

NSString *decode = [encode stringByReplacingPercentEscapesUsingEncoding:NSUTF8StringEncoding];

Questo è inaccurato. Ti consigliamo di fuggire in modo diverso parti diverse dell'URL. stackoverflow.com/questions/3423545/…
Steve Moser,

In realtà dipende dal tuo server per i caratteri consentiti, qui sul mio esempio nel server che stavo usando ha consentito solo il set di caratteri alfanumerici, puoi cambiarlo in caratteri specifici per soddisfare le tue esigenze.
Underdog

1
La domanda è sulla codifica del carattere "&".
Steve Moser,

8

Ho scelto di utilizzare la CFURLCreateStringByAddingPercentEscapeschiamata come indicato dalla risposta accettata, tuttavia nella versione più recente di XCode (e IOS), si è verificato un errore, quindi ho usato invece il seguente:

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

Non sta codificando lo spazio. Esempio @ "stringa stringa" e @ "stringa e stringa" sono codificati correttamente. Per favore fatemi sapere il vostro contributo sullo stesso.
Yogesh Lolusare il

2
per me la maggior parte del tempo trascorso a risolvere questo è stato il periodo di negazione in cui mi sono rifiutato di credere che il framework non contenga qualcosa di simile a "urlencode" che lo fa senza il
caos

6

Prova a usare il stringByAddingPercentEncodingWithAllowedCharactersmetodo con[NSCharacterSet URLUserAllowedCharacterSet] esso coprirà tutti i casi

Obiettivo C

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

veloce

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

Produzione

Test%20%2F%20Test


6

Dopo aver letto tutte le risposte per questo argomento e quella ( sbagliata ) accettata, voglio aggiungere il mio contributo.

SE l'obiettivo è iOS7 +, e nel 2017 dovrebbe essere molto difficile offrire compatibilità con iOS 8, poiché il modo migliore, thread thread sicuro, veloce, e il pieno supporto UTF-8 per farlo è:

(Codice obiettivo C)

@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

Ciò estenderà NSString, escluderà i caratteri vietati RFC, supporterà i caratteri UTF-8 e ti consentirà di usare cose come:

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

Che verrà stampato sulla tua console di debug:

Fonte: I'm [evil] & want (to) break !!! $ -> àéìòù -> Dest: I% 27m% 5Bevil% 5D% 26want% 28to% 29break% 21% 21% 21% 24-% 3E% C3 % A0% C3% A9% C3% AC% C3% B2% C3% B9

... nota anche l'uso di dispatch_once per evitare inizializzazioni multiple in ambienti multithread.


5

Ecco un approccio flessibile pronto per la produzione in 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())
    }
}

Esempio di utilizzo:

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

Produzione:

Hello,%20World!
You%26Me%3F
%23Blessed%20100%25
%50ride and %50rejudice

Per favore, includi un commento che spieghi il motivo dei tuoi voti negativi, quindi so come scrivere una risposta migliore in futuro 🙂
Ben Leggiero,

4

Utilizzare i componenti NSURLC per codificare i parametri HTTP GET:

    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/


1
Non codifica e commerciali, barre o punti e virgola.
Fábio Oliveira,

4

Questo codice mi ha aiutato a codificare caratteri speciali

NSString* encPassword = [password stringByAddingPercentEncodingWithAllowedCharacters:[NSCharacterSet alphanumericCharacterSet]];

3

codice rapido basato sulla risposta objc di chown in questo thread.

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

4
questa funzione è stata deprecata in iOS 9 :(
Oliver Atkinson il

3

In Swift 3 , prova di seguito:

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

Poiché, stringByAddingPercentEscapesUsingEncodingcodifica caratteri non URL ma lascia i caratteri riservati (come !*'();:@&=+$,/?%#[]), è possibile codificare l'URL come il seguente codice:

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

2

In rapido 3:

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

// exclude hostname and symbols &,/ and etc
stringUrl = stringUrl.addingPercentEncoding(withAllowedCharacters: .urlHostAllowed)!;

2

Il consiglio di Apple, nelle note di rilascio della 10.11, è:

Se devi codificare in percentuale una stringa URL intera, puoi utilizzare questo codice per codificare un NSString destinato ad essere un URL (in urlStringToEncode):

NSString *percentEncodedURLString =
  [[NSURL URLWithDataRepresentation:[urlStringToEncode dataUsingEncoding:NSUTF8StringEncoding] relativeToURL:nil] relativeString];

non sembra funzionare, personaggi come e sono ancora lasciati soli
kjyv

1

Nel mio caso in cui l'ultimo componente era costituito da lettere arabe, ho fatto quanto segue 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;
}
}

utilizzo:

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

if let encodedStringURL = stringURL.encodeUTF8() {

    if let url = NSURL(string: encodedStringURL) {

      ...
    }

} 

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

secondo il seguente blog


Ma è obsoleto in iOS 9. Qual è il codice aggiornato per questo?
Sujit Nachan,

1

Così tante risposte ma non ha funzionato per me, quindi ho provato quanto segue:

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

Spero che possa aiutare qualcuno. Grazie


0

Per i singoli parametri di query codificati in forma www, ho creato una categoria su NSString:

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

0

// Questo è senza test

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

0

Ho riscontrato un problema simile passando stringhe complesse come parametro POST. Le mie stringhe possono contenere caratteri asiatici, spazi, virgolette e tutti i tipi di caratteri speciali. La soluzione che ho trovato alla fine è stata quella di convertire la mia stringa nella serie di unicode corrispondente, ad esempio "Hu0040Hu0020Hu03f5 ...." utilizzando [NSString stringWithFormat: @ "Hu% 04x", [string characterAtIndex: i]] per ottenere l'Unicode da ciascuno carattere nella stringa originale. Lo stesso può essere fatto in Java.

Questa stringa può essere tranquillamente passata come parametro POST.

Sul lato server (PHP), cambio tutta la "H" in "\" e passo la stringa risultante a json_decode. Il passaggio finale consiste nell'evitare le virgolette singole prima di archiviare la stringa in MySQL.

In questo modo posso memorizzare qualsiasi stringa UTF8 sul mio server.


0

Questo funziona per me.

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
}

Ho trovato la funzione sopra da questo link: http://useyourloaf.com/blog/how-to-percent-encode-a-url-string/

È inoltre possibile utilizzare questa funzione con estensione rapida. Per favore fatemi sapere se c'è qualche problema.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.