74 votes

Objective-c iPhone pour encoder une chaîne de caractères ?

Je voudrais obtenir la chaîne encodée en pourcentage pour ces lettres spécifiques, comment faire cela en Objective-C ?

Reserved characters after percent-encoding
!   *   '   (   )   ;   :   @   &   =   +   $   ,   /   ?   #   [   ]
%21 %2A %27 %28 %29 %3B %3A %40 %26 %3D %2B %24 %2C %2F %3F %23 %5B %5D

Wiki de codage en pourcentage

Veuillez tester cette chaîne et voir si elle fonctionne :

myURL = @"someurl/somecontent"

Je voudrais que la chaîne ressemble à :

myEncodedURL = @"someurl%2Fsomecontent"

J'ai essayé avec le stringByAddingPercentEscapesUsingEncoding: NSASCIIStringEncoding déjà mais cela ne fonctionne pas, le résultat est toujours le même que la chaîne originale. Veuillez me conseiller.

0 votes

Vous devriez ajouter % à cette liste.

0 votes

Je ne comprends pas votre commentaire :-s

0 votes

Il veut dire que le % doit lui-même être codé en URL. Ainsi, une chaîne d'entrée comme %2F se transformera en %252F . Je suggère également d'ajouter le caractère espace ( %20 ) à cette liste.

145voto

Dave DeLong Points 156978

J'ai trouvé que les deux stringByAddingPercentEscapesUsingEncoding: et CFURLCreateStringByAddingPercentEscapes() sont inadéquates. Le site NSString manque un certain nombre de caractères, et la fonction CF ne vous permet que de dire quels caractères (spécifiques) vous voulez échapper. La spécification correcte est d'échapper tous les caractères sauf un petit ensemble.

Pour résoudre ce problème, j'ai créé un NSString pour encoder correctement une chaîne de caractères. Elle codera en pourcentage tout ce qui est EXCEPTÉ [a-zA-Z0-9.-_~] et codera également les espaces comme + (selon cette spécification ). Il gèrera également correctement l'encodage des caractères unicode.

- (NSString *) URLEncodedString_ch {
    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;
}

7 votes

Notez que l'encodage des espaces sous forme de + au lieu de %20 est conforme à la norme x-www-form-urlencoded, et non à la norme oauth-1,3.6 (lien vers la spécification que vous avez publiée).

6 votes

@mihir bien sûr. C'est juste une méthode de conversion. Si vous ne voulez pas qu'une chaîne entière soit encodée, ne passez pas la chaîne entière...

3 votes

J'ai compris votre point de vue, en fait j'ai tout implémenté et je me suis rendu compte de ce problème, j'ai besoin de coder chaque paramètre individuellement maintenant ... très lourd ... :(

107voto

Le SDK d'iOS 7 dispose désormais d'une meilleure solution de rechange pour stringByAddingPercentEscapesUsingEncoding qui vous permet de spécifier que vous voulez que tous les caractères soient échappés sauf certains caractères autorisés. Cela fonctionne bien si vous construisez l'URL en plusieurs parties :

NSString * unescapedQuery = [[NSString alloc] initWithFormat:@"?myparam=%d", numericParamValue];
NSString * escapedQuery = [unescapedQuery stringByAddingPercentEncodingWithAllowedCharacters:[NSCharacterSet URLQueryAllowedCharacterSet]];
NSString * urlString = [[NSString alloc] initWithFormat:@"http://ExampleOnly.com/path.ext%@", escapedQuery];

Bien qu'il soit moins fréquent que les autres parties de l'URL soient des variables, il existe des constantes dans la catégorie NSURLUtilities pour celles-ci également :

[NSCharacterSet URLHostAllowedCharacterSet]
[NSCharacterSet URLUserAllowedCharacterSet]
[NSCharacterSet URLPasswordAllowedCharacterSet]
[NSCharacterSet URLPathAllowedCharacterSet]
[NSCharacterSet URLFragmentAllowedCharacterSet]

[NSCharacterSet URLQueryAllowedCharacterSet] comprend tous des caractères autorisés dans la partie "requête" de l'URL (la partie commençant par le symbole ? et avant le # pour un fragment, le cas échéant), y compris le ? y el & ou = qui sont utilisés pour délimiter les noms et les valeurs des paramètres. Pour les paramètres de requête ayant des valeurs alphanumériques, n'importe lequel de ces caractères peut être inclus dans les valeurs des variables utilisées pour construire la chaîne de requête. Dans ce cas, chaque partie de la chaîne de requête doit être échappée, ce qui nécessite un peu plus de travail :

NSMutableCharacterSet * URLQueryPartAllowedCharacterSet; // possibly defined in class extension ...

// ... and built in init or on first use
URLQueryPartAllowedCharacterSet = [[NSCharacterSet URLQueryAllowedCharacterSet] mutableCopy];
[URLQueryPartAllowedCharacterSet removeCharactersInString:@"&+=?"]; // %26, %3D, %3F

// then escape variables in the URL, such as values in the query and any fragment:
NSString * escapedValue = [anUnescapedValue stringByAddingPercentEncodingWithAllowedCharacters:URLQueryPartAllowedCharacterSet];
NSString * escapedFrag = [anUnescapedFrag stringByAddingPercentEncodingWithAllowedCharacters:[NSCharacterSet URLFragmentAllowedCharacterSet]];
NSString * urlString = [[NSString alloc] initWithFormat:@"http://ExampleOnly.com/path.ext?myparam=%@#%@", escapedValue, escapedFrag];
NSURL * url = [[NSURL alloc] initWithString:urlString];

El unescapedValue peut même être une URL entière, par exemple pour un rappel ou une redirection :

NSString * escapedCallbackParamValue = [anAlreadyEscapedCallbackURL stringByAddingPercentEncodingWithAllowedCharacters:URLQueryPartAllowedCharacterSet];
NSURL * callbackURL = [[NSURL alloc] initWithString:[[NSString alloc] initWithFormat:@"http://ExampleOnly.com/path.ext?callback=%@", escapedCallbackParamValue]];

Note : N'utilisez pas NSURL initWithScheme:(NSString *)scheme host:(NSString *)host path:(NSString *)path pour une URL avec une chaîne de requête, car cela ajoutera plus d'échappatoires de pourcentage au chemin.

1 votes

Cela devrait être la réponse principale. Elle est à jour avec les utilitaires d'iOS7, et elle note correctement que les différentes parties de l'URL doivent être échappées différemment.

2 votes

Il manque juste le '+' donc vous pourriez ajouter [URLQueryPartAllowedCharacterSet removeCharactersInRange:NSMakeRange('+', 1)]; mais sinon ce code est parfait pour l'échappement des chaînes de caractères, merci !

9 votes

Il y a une alternative moins verbeuse : URLQueryPartAllowedCharacterSet = [[NSCharacterSet URLQueryAllowedCharacterSet] mutableCopy]; [URLQueryPartAllowedCharacterSet removeCharactersInString:@"?&=@+/'"]; J'ai également testé 100 000 itérations sur un Mac et j'ai constaté que cette méthode était toujours un peu plus rapide que l'appel à la fonction removeCharactersInRange: plusieurs fois.

5voto

Dan Ray Points 14852
NSString *encodedString = [myString stringByAddingPercentEscapesUsingEncoding:NSASCIIStringEncoding];

Elle ne remplacera pas votre chaîne de caractères en ligne ; elle retournera une nouvelle chaîne de caractères. C'est ce qu'implique le fait que la méthode commence par le mot "string". C'est une méthode pratique pour instancier une nouvelle instance de NSString basée sur la NSString actuelle.

Remarque : cette nouvelle chaîne sera autorelease alors n'appelez pas la libération quand vous en aurez fini.

0 votes

Merci, mais cela ne fonctionne pas, veuillez vérifier ma question mise à jour.

2 votes

Le résultat est toujours le même, il n'y a pas de changement.

5voto

David Points 2133

L'élément NSString stringByAddingPercentEscapesUsingEncoding : ressemble à ce que vous cherchez.

EDIT : Voici un exemple utilisant CFURLCreateStringByAddingPercentEscapes à la place. originalString peut être soit un NSString ou un CFStringRef .

CFStringRef newString = CFURLCreateStringByAddingPercentEscapes(kCFAllocatorDefault, originalString, NULL, CFSTR("!*'();:@&=+@,/?#[]"), kCFStringEncodingUTF8);

Veuillez noter que ce système n'a pas été testé. Vous devriez jeter un coup d'œil à la page de documentation pour s'assurer que vous comprenez la sémantique de l'allocation de la mémoire pour CFStringRef l'idée d'une passerelle sans frais, et ainsi de suite.

De plus, je ne sais pas (de mémoire) quels sont les caractères spécifiés dans le champ legalURLCharactersToBeEscaped aurait été échappé de toute façon (parce qu'il est illégal dans les URLs). Vous pouvez vérifier cela, bien qu'il soit peut-être préférable d'être prudent et de spécifier directement les caractères que vous voulez échapper.

Je fais de cette réponse un wiki communautaire afin que les personnes ayant plus de connaissances sur CoreFoundation puissent apporter des améliorations.

0 votes

Quel NSStringEcoding dois-je utiliser pour que tous les caractères ci-dessus fonctionnent correctement ? Avez-vous essayé avec une chaîne de caractères ?

0 votes

Hmm, il n'y a pas l'air d'y avoir un NSStringEncoding valeur pour ce que vous voulez. Vous pouvez essayer CFURLCreateStringByAddingPercentEscapes ( developer.apple.com/mac/library/documentation/CoreFoundation/ ) à la place - il vous permet de spécifier directement les caractères à échapper.

0 votes

...oh, et au fait : NSString et CFStringRef sont "pontés sans frais", ce qui signifie qu'ils peuvent être transmis de manière interchangeable aux fonctions de l'autre.

2voto

bhavinb Points 2441

Si vous utilisez Bibliothèque ASI HttpRequest dans votre programme objective-c, que je ne saurais trop vous recommander, alors vous pouvez utiliser l'API d'aide "encodeURL" sur son objet ASIFormDataRequest. Malheureusement, l'API n'est pas statique, donc cela vaut peut-être la peine de créer une extension utilisant son implémentation dans votre projet.

Le code, copié directement de l'implémentation de l'ASIFormDataRequest.m pour encodeURL, est le suivant :

- (NSString*)encodeURL:(NSString *)string
{
    NSString *newString = NSMakeCollectable([(NSString *)CFURLCreateStringByAddingPercentEscapes(kCFAllocatorDefault, (CFStringRef)string, NULL, CFSTR(":/?#[]@!$ &'()*+,;=\"<>%{}|\\^~`"), CFStringConvertNSStringEncodingToEncoding([self stringEncoding])) autorelease]);
    if (newString) {
        return newString;
    }
    return @"";
}

Comme vous pouvez le voir, il s'agit essentiellement d'un emballage autour de CFURLCreateStringByAddingPercentEscapes qui s'occupe de tous les caractères qui doivent être correctement échappés.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X