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 /

chown
la source
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.

Nishant
la source
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];
Peter DeWeese
la source
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

  }

}
Oliver Atkinson
la source
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];
Underdog
la source
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));
Mike Purcell
la source
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

Alex
la source
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.

Gabry
la source
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
Ben Leggiero
la source
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/

Ralf Ebert
la source
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]];
Rupesh Baldania
la source
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
        )
    }
}
neoneye
la source
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)
}
Dinesh
la source
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)!;
mer-kg
la source
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];
nithinbhaktha
la source
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) {

      ...
    }

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

selon le blog suivant

Anton Kashpor
la source
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

Sanjeevcn
la source
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;
}
Pete Kamm
la source
0

// Ceci est sans test

NSMutableCharacterSet* set = [[NSCharacterSet alphanumericCharacterSet] mutableCopy];
[set addCharactersInString:@"-_.~"];
NSString *encode = [test stringByAddingPercentEncodingWithAllowedCharacters:set];
Achille Wang
la source
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.

Georges
la source
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.

Gaurav Singla
la source