Comment encoder une chaîne en URL


Réponses:


291

Malheureusement, stringByAddingPercentEscapesUsingEncodingcela ne fonctionne pas toujours à 100%. Il encode les caractères non URL mais laisse les caractères réservés (comme la barre oblique /et l'esperluette &) seuls. Apparemment, c'est un bogue dont Apple est conscient, mais comme ils ne l'ont pas encore corrigé, j'utilise cette catégorie pour encoder une chaîne en url:

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

Utilisé comme ceci:

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

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

Cela fonctionne également:

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

Quelques bonnes lectures sur le sujet:

Objectif-c iPhone pour cent encoder une chaîne?
Encodage URL Objective-C et Swift

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
Pourquoi diable utiliseriez-vous une catégorie compliquée comme celle-ci plutôt que de simplement passer à CFURLCreateStringByAddingPercentEscapes () , où vous pouvez spécifier explicitement les caractères que vous voulez toujours échapper.
Lily Ballard

8
@KevinBallard car la fonction CF fonctionne sur un modèle inclusif ("échapper à ces caractères"), et généralement vous voulez travailler sur un modèle exclusif ("échapper à tout sauf ces caractères")
Dave DeLong


31
@DaveDeLong C'est peut-être là que je l'ai eu. C'est une catégorie standard dans tous mes projets depuis environ un an, alors j'imagine que vous en avez peut-être été la source originale! J'ai édité le libellé donc il ne semble pas que j'essaie de m'attribuer le mérite de l'avoir écrit).
chown

4
Pourquoi? if (thisChar == '') {[output appendString: @ "+"]; } Sans cela, s'il encodera les espaces avec% 20 comme je m'y attendais
Chris Stephens

127

Cela pourrait être utile

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

Pour iOS 7+, la méthode recommandée est:

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

Vous pouvez choisir le jeu de caractères autorisé selon les exigences du composant URL.


7
Cela n'encode pas non plus correctement les délimiteurs de paramètres tels que «&», «?» dans le cas où vous transmettez du contenu dans une API.
Ben Lachman

«&» n'est pas un caractère valide pour le paramètre de chaîne de requête URL. Veuillez essayer d'utiliser «& amp;» au lieu.
Nishant le

1
stringByAddingPercentEscapesUsingEncoding is DEPRECATED "À utiliser à la -stringByAddingPercentEncodingWithAllowedCharacters:place, qui utilise toujours le codage UTF-8 recommandé et qui code pour un composant ou sous-composant URL spécifique, car chaque composant ou sous-composant URL a des règles différentes pour les caractères valides."
Mihir Oza

89

De nouvelles API ont été ajoutées depuis que la réponse a été sélectionnée; Vous pouvez maintenant utiliser NSURLUtilities. Étant donné que différentes parties des URL autorisent différents caractères, utilisez le jeu de caractères applicable. L'exemple suivant code pour l'inclusion dans la chaîne de requête:

encodedString = [myString stringByAddingPercentEncodingWithAllowedCharacters:NSCharacterSet.URLQueryAllowedCharacterSet];

Pour convertir spécifiquement «&», vous devez le supprimer de l'ensemble de requêtes URL ou utiliser un ensemble différent, car «&» est autorisé dans une requête URL:

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

1
Il m'a fallu un certain temps pour comprendre ce que vous vouliez dire par «utiliser NSURLUtilities» - mais maintenant je vois que c'est le nom de la catégorie de NSString dans laquelle Apple a défini cette nouvelle méthode dans iOS 7 et OS X 10.9.
Richard Venable

1
Il y a une réponse plus élaborée comme celle-ci ici: stackoverflow.com/a/20271177/456366
Richard Venable

Ouaip. Il a également été répertorié comme NSURLUtilities dans la liste des nouvelles API publiées.
Peter DeWeese

'&' est bien sûr autorisé dans une chaîne de requête, je vais donc modifier ma réponse en utilisant le lien de Richard.
Peter DeWeese

3
NSMakeRange('&', 1)ne fonctionne pas dans Swift, car Swift n'autorise pas la conversion de caractères en int sans hacks. Pour utiliser cette solution en code Swift, utilisez à la removeCharactersInString("&")place de.removeCharactersInRange(...)
cbh2000

16

Exemple de Swift 2.0 (compatible avec iOS 9)

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 vous semblez devoir sauter à travers quelques cerceaux pour arriver ici, c'est pourquoi il vaut mieux le cacher dans une extension
Oliver Atkinson

@OliverAtkinson - pour moi Int (String (Character ("&"))) renvoie nil, comme il se doit. Au lieu de cela characters.removeCharactersInString ("&").
ambientlight

14

mise à jour ios 7

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

NSString *decode = [encode stringByReplacingPercentEscapesUsingEncoding:NSUTF8StringEncoding];

Ceci est inexact. Vous voudrez échapper différemment aux différentes parties de l'URL. stackoverflow.com/questions/3423545/…
Steve Moser

Cela dépend en fait de votre serveur pour les caractères autorisés, ici, sur mon exemple sur le serveur que je l'utilisais, il ne permettait que le jeu de caractères alphanumériques autorisé, vous pouvez le changer en caractères spécifiques pour répondre à vos besoins.
Underdog

1
La question porte sur l'encodage du caractère «&».
Steve Moser

8

J'ai choisi d'utiliser l' CFURLCreateStringByAddingPercentEscapesappel tel que donné par la réponse acceptée, mais dans la dernière version de XCode (et IOS), cela a entraîné une erreur, j'ai donc utilisé ce qui suit à la place:

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

Ce n'est pas de l'espace d'encodage. Exemple @ "string string" et @ "string & string" sont codés correctement. S'il vous plaît laissez-moi savoir votre avis sur le même.
Yogesh Lolusare

2
pour moi, la plupart du temps passé à résoudre ce problème a été la période de refus où j'ai refusé de croire que le cadre ne contenait pas quelque chose de nommé similaire à 'urlencode' qui le fait sans déconner ..
dancl

6

Essayez d'utiliser la stringByAddingPercentEncodingWithAllowedCharactersméthode avec [NSCharacterSet URLUserAllowedCharacterSet]elle couvrira tous les cas

Objectif c

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

rapide

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

Production

Test%20%2F%20Test


6

Après avoir lu toutes les réponses à ce sujet et la ( mauvaise ) acceptée, je veux ajouter ma contribution.

SI la cible est iOS7 +, et en 2017, cela devrait, puisque XCode rend vraiment difficile la compatibilité sous iOS8, le meilleur moyen, sûr pour les threads, rapide, amd prendra entièrement en charge UTF-8 pour ce faire est:

(Code objectif 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

Cela étendra NSString, exclura les caractères interdits RFC, prendra en charge les caractères UTF-8 et vous permettra d'utiliser des choses comme:

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

Cela s'imprimera sur votre console de débogage:

Source: 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

... notez également l'utilisation de dispatch_once pour éviter de multiples initialisations dans les environnements multithread.


5

Voici une approche flexible prête pour la production dans 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())
    }
}

Exemple d'utilisation:

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

Production:

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

Veuillez inclure un commentaire expliquant la raison de vos votes négatifs afin que je sache comment écrire une meilleure réponse à l'avenir 🙂
Ben Leggiero

4

Utilisez NSURLComponents pour coder les paramètres 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
Il n'encode pas les esperluettes, les barres obliques ou les points-virgules.
Fábio Oliveira

4

Ce code m'a aidé à encoder des caractères spéciaux

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

3

code swift basé sur la réponse objc de chown dans ce fil.

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

4
cette fonction était obsolète dans iOS 9 :(
Oliver Atkinson

3

Dans Swift 3 , veuillez essayer ci-dessous:

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

Depuis, stringByAddingPercentEscapesUsingEncodingencode les caractères non URL mais laisse les caractères réservés (comme !*'();:@&=+$,/?%#[]), vous pouvez encoder l'url comme le code suivant:

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

2

Dans Swift 3:

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

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

2

Le conseil d'Apple, dans les notes de version 10.11, est:

Si vous devez encoder en pourcentage une chaîne d'URL entière, vous pouvez utiliser ce code pour encoder une NSString destinée à être une URL (dans urlStringToEncode):

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

ne semble pas fonctionner, les personnages aiment et sont toujours laissés seuls
kjyv

1

Dans mon cas où le dernier composant était des lettres arabes, j'ai fait ce qui suit dans 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;
}
}

usage:

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

selon le blog suivant


Mais il est obsolète dans iOS 9. Quel est le code mis à jour pour cela?
Sujit Nachan

1

Tant de réponses mais cela n'a pas fonctionné pour moi, alors j'ai essayé ce qui suit:

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

J'espère que cela aidera quelqu'un. Merci


0

Pour les paramètres de requête codés par formulaire www, j'ai créé une catégorie sur NSString:

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

0

// Ceci est sans test

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

0

J'ai rencontré un problème similaire en passant des chaînes complexes en tant que paramètre POST. Mes chaînes peuvent contenir des caractères asiatiques, des espaces, des guillemets et toutes sortes de caractères spéciaux. La solution que j'ai finalement trouvée a été de convertir ma chaîne dans la série correspondante d'Unicodes, par exemple "Hu0040Hu0020Hu03f5 ...." en utilisant [NSString stringWithFormat: @ "Hu% 04x", [string characterAtIndex: i]] pour obtenir l'Unicode de chaque caractère dans la chaîne d'origine. La même chose peut être faite en Java.

Cette chaîne peut être transmise en toute sécurité en tant que paramètre POST.

Côté serveur (PHP), je change tous les "H" en "\" et je passe la chaîne résultante à json_decode. La dernière étape consiste à échapper les guillemets simples avant de stocker la chaîne dans MySQL.

De cette façon, je peux stocker n'importe quelle chaîne UTF8 sur mon serveur.


0

Celui-ci fonctionne pour moi.

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
}

J'ai trouvé la fonction ci-dessus à partir de ce lien: http://useyourloaf.com/blog/how-to-percent-encode-a-url-string/

Vous pouvez également utiliser cette fonction avec l'extension rapide. S'il vous plaît laissez-moi savoir s'il y a un problème.

En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.