web-dev-qa-db-fra.com

NSURL extraire une seule valeur pour une clé dans une chaîne de paramètres

J'ai un NSURL: 

serverCall? x = a & y = b & z = c

Quel est le moyen le plus rapide et le plus efficace d’obtenir la valeur de y? 

Merci

43
Dave

METTRE À JOUR:

Depuis 2010, année de la rédaction de cet article, il semble qu'Apple ait publié un ensemble d'outils à cette fin. S'il vous plaît voir les réponses ci-dessous pour ceux-ci.

Solution vieille école:

Eh bien, je sais que vous avez dit "le moyen le plus rapide} _" mais après avoir commencé à faire un test avec NSScanner, je ne pouvais tout simplement pas m'arrêter. Et bien que ce ne soit pas le moyen le plus court, il est certainement utile si vous envisagez d’utiliser beaucoup cette fonctionnalité. J'ai créé une classe URLParser qui obtient ces vars à l'aide d'une NSScanner. L'utilisation est simple comme:

URLParser *parser = [[[URLParser alloc] initWithURLString:@"http://blahblahblah.com/serverCall?x=a&y=b&z=c&flash=yes"] autorelease];
NSString *y = [parser valueForVariable:@"y"];
NSLog(@"%@", y); //b
NSString *a = [parser valueForVariable:@"a"];
NSLog(@"%@", a); //(null)
NSString *flash = [parser valueForVariable:@"flash"];
NSLog(@"%@", flash); //yes

Et la classe qui fait cela est la suivante (* fichiers source au bas de l'article):

URLParser.h

@interface URLParser : NSObject {
    NSArray *variables;
}

@property (nonatomic, retain) NSArray *variables;

- (id)initWithURLString:(NSString *)url;
- (NSString *)valueForVariable:(NSString *)varName;

@end

URLParser.m

@implementation URLParser
@synthesize variables;

- (id) initWithURLString:(NSString *)url{
    self = [super init];
    if (self != nil) {
        NSString *string = url;
        NSScanner *scanner = [NSScanner scannerWithString:string];
        [scanner setCharactersToBeSkipped:[NSCharacterSet characterSetWithCharactersInString:@"&?"]];
        NSString *tempString;
        NSMutableArray *vars = [NSMutableArray new];
        [scanner scanUpToString:@"?" intoString:nil];       //ignore the beginning of the string and skip to the vars
        while ([scanner scanUpToString:@"&" intoString:&tempString]) {
            [vars addObject:[tempString copy]];
        }
        self.variables = vars;
        [vars release];
    }
    return self;
}

- (NSString *)valueForVariable:(NSString *)varName {
    for (NSString *var in self.variables) {
        if ([var length] > [varName length]+1 && [[var substringWithRange:NSMakeRange(0, [varName length]+1)] isEqualToString:[varName stringByAppendingString:@"="]]) {
            NSString *varValue = [var substringFromIndex:[varName length]+1];
            return varValue;
        }
    }
    return nil;
}

- (void) dealloc{
    self.variables = nil;
    [super dealloc];
}

@end

* Si vous n'aimez pas copier et coller, vous pouvez simplement télécharger les fichiers sources - j'ai écrit un article rapide sur ce blog ici .

80
Dimitris

Souvenez-vous de tant d’analyseurs d’URL personnalisés NSURLComponents est votre ami!

Voici un exemple où je tire un paramètre encodé dans l'URL pour "page"

Rapide

let myURL = "www.something.com?page=2"

var pageNumber : Int?
if let queryItems = NSURLComponents(string: myURL)?.queryItems {
    for item in queryItems {
        if item.name == "page" {
           if let itemValue = item.value {
               pageNumber = Int(itemValue)
           }
        }
    }
}
print("Found page number: \(pageNumber)")

Objectif c

NSString *myURL = @"www.something.com?page=2";
NSURLComponents *components = [NSURLComponents componentsWithString:myURL];
NSNumber *page = nil;
for(NSURLQueryItem *item in components.queryItems)
{
    if([item.name isEqualToString:@"page"])
        page = [NSNumber numberWithInteger:item.value.integerValue];
}

"Pourquoi réinventer la roue!" - Quelqu'un intelligent

63
anders

Je suis presque sûr que vous devez l'analyser vous-même. Cependant, ce n'est pas si mal:

NSString * q = [myURL query];
NSArray * pairs = [q componentsSeparatedByString:@"&"];
NSMutableDictionary * kvPairs = [NSMutableDictionary dictionary];
for (NSString * pair in pairs) {
  NSArray * bits = [pair componentsSeparatedByString:@"="];
  NSString * key = [[bits objectAtIndex:0] stringByReplacingPercentEscapesUsingEncoding:NSUTF8StringEncoding];
  NSString * value = [[bits objectAtIndex:1] stringByReplacingPercentEscapesUsingEncoding:NSUTF8StringEncoding];
  [kvPairs setObject:value forKey:key];
}

NSLog(@"y = %@", [kvPairs objectForKey:@"y"]);
19
Dave DeLong

Dans Swift, vous pouvez utiliser NSURLComponents pour analyser la chaîne de requête d'un NSURL dans un [AnyObject]. 

Vous pouvez ensuite créer un dictionnaire (ou accéder directement aux éléments) pour obtenir les paires clé/valeur. A titre d'exemple, voici ce que j'utilise pour analyser une URL de variable NSURL:

let urlComponents = NSURLComponents(URL: url, resolvingAgainstBaseURL: false)
let items = urlComponents?.queryItems as [NSURLQueryItem]
var dict = NSMutableDictionary()
for item in items{
    dict.setValue(item.value, forKey: item.name)
}
println(dict["x"])
11
leafcutter

J'utilise cette catégorie: https://github.com/carlj/NSURL-Parameters .

C'est petit et facile à utiliser:

#import "NSURL+Parameters.h"
...
NSURL *url = [NSURL URLWithString:@"http://foo.bar.com?paramA=valueA&paramB=valueB"];
NSString *paramA = url[@"paramA"];
NSString *paramB = url[@"paramB"];
10
Troy

Vous pouvez utiliser Google Toolbox for Mac . Il ajoute une fonction à NSString pour convertir la chaîne de requête en dictionnaire.

http://code.google.com/p/google-toolbox-for-mac/

Il fonctionne comme un charme

        NSDictionary * d = [NSDictionary gtm_dictionaryWithHttpArgumentsString:[[request URL] query]];
4
ventayol

Voici une extension Swift 2.0 offrant un accès simple aux paramètres:

extension NSURL {
    var params: [String: String] {
        get {
            let urlComponents = NSURLComponents(URL: self, resolvingAgainstBaseURL: false)
            var items = [String: String]()
            for item in urlComponents?.queryItems ?? [] {
                items[item.name] = item.value ?? ""
            }
            return items
        }
    }
} 

Exemple d'utilisation:

let url = NSURL(string: "http://google.com?test=dolphins")
if let testParam = url.params["test"] {
    print("testParam: \(testParam)")
}
4
Albert Bori

J'ai écrit une catégorie simple pour étendre NSString/NSURL qui vous permet d'extraire les paramètres de requête d'URL individuellement ou sous la forme d'un dictionnaire de paires clé/valeur:

https://github.com/nicklockwood/RequestUtils

3
Nick Lockwood

Je l'ai fait en utilisant une méthode de catégorie basée sur la solution @Dimitris

#import "NSURL+DictionaryValue.h"

@implementation NSURL (DictionaryValue)
-(NSDictionary *)dictionaryValue
{
NSString *string =  [[self.absoluteString stringByReplacingOccurrencesOfString:@"+" withString:@" "]
                     stringByReplacingPercentEscapesUsingEncoding:NSUTF8StringEncoding];
NSScanner *scanner = [NSScanner scannerWithString:string];
[scanner setCharactersToBeSkipped:[NSCharacterSet characterSetWithCharactersInString:@"&?"]];

NSString *temp;
NSMutableDictionary *dict = [[[NSMutableDictionary alloc] init] autorelease];
[scanner scanUpToString:@"?" intoString:nil];       //ignore the beginning of the string and skip to the vars
while ([scanner scanUpToString:@"&" intoString:&temp]) 
{
    NSArray *parts = [temp componentsSeparatedByString:@"="];
    if([parts count] == 2)
    {
        [dict setObject:[parts objectAtIndex:1] forKey:[parts objectAtIndex:0]];
    }
}

return dict;
}
@end
2
odyth

Voici la réponse acceptée en tant que catégorie:

@implementation NSURL(Parsing)

- (NSString *)valueForParameterWithKey:(NSString *)key {
    for (NSString *var in self.parameterKeys) {
        if (var.length > key.length+1 && [[var substringWithRange:NSMakeRange(0, key.length+1)] isEqualToString:[key stringByAppendingString:@"="]]) {
            NSString *varValue = [var substringFromIndex:key.length+1];
            return varValue;
        }
    }
    return nil;
}

- (NSArray<NSString *> *)parameterKeys {
    NSScanner *scanner = [NSScanner scannerWithString:self.absoluteString];
    [scanner setCharactersToBeSkipped:[NSCharacterSet characterSetWithCharactersInString:@"&?"]];
    NSString *tempString;
    NSMutableArray *vars = [NSMutableArray new];
    [scanner scanUpToString:@"?" intoString:nil];
    while ([scanner scanUpToString:@"&" intoString:&tempString]) {
        [vars addObject:tempString.copy];
    }
    return vars;
}

@end
0
Brian Semiglia

Vous pouvez faire ça facilement:

- (NSMutableDictionary *) getUrlParameters:(NSURL *) url
{
    NSMutableDictionary *params = [[NSMutableDictionary alloc] init];
    NSString *tmpKey = [url query];
    for (NSString *param in [[url query] componentsSeparatedByString:@"="])
    {
        if ([tmpKey rangeOfString:param].location == NSNotFound)
        {
            [params setValue:param forKey:tmpKey];
            tmpKey = nil;
        }
        tmpKey = param;
    }
    [tmpKey release];

    return params;
}

Il retourne un dictionnaire comme celui-ci: Key = value

0
tryp

Toutes les réponses actuelles sont spécifiques à la version ou inutiles. Pourquoi créer un dictionnaire si vous ne voulez qu'une seule valeur?

Voici un simple réponse prenant en charge toutes les versions d'iOS:

- (NSString *)getQueryParam:(NSString *)name  fromURL:(NSURL *)url
{
    if (url)
    {
        NSArray *urlComponents = [url.query componentsSeparatedByString:@"&"];
        for (NSString *keyValuePair in urlComponents)
        {
            NSArray *pairComponents = [keyValuePair componentsSeparatedByString:@"="];
            NSString *key = [[pairComponents firstObject] stringByRemovingPercentEncoding];

            if ([key isEqualToString:name])
            {
                return [[pairComponents lastObject] stringByRemovingPercentEncoding];
            }
        }
    }
    return nil;
}
0
IanS

J'ai légèrement modifié le code de Dimitris pour une meilleure gestion de la mémoire et une efficacité accrue. En outre, cela fonctionne dans l'ARC.

URLParser.h

@interface URLParser : NSObject

- (void)setURLString:(NSString *)url;
- (NSString *)valueForVariable:(NSString *)varName;

@end

URLParser.m

#import "URLParser.h"

@implementation URLParser {
    NSMutableDictionary *_variablesDict;
}

- (void)setURLString:(NSString *)url {
    [_variablesDict removeAllObjects];

    NSString *string = url;
    NSScanner *scanner = [NSScanner scannerWithString:string];
    [scanner setCharactersToBeSkipped:[NSCharacterSet characterSetWithCharactersInString:@"&?"]];
    NSString *tempString;

    [scanner scanUpToString:@"?" intoString:nil];       //ignore the beginning of the string and skip to the vars
    while ([scanner scanUpToString:@"&" intoString:&tempString]) {
        NSString *dataString = [tempString copy];
        NSArray *sepStrings = [dataString componentsSeparatedByString:@"="];
        if ([sepStrings count] == 2) {
            [_variablesDict setValue:sepStrings[1] forKeyPath:sepStrings[0]];
        }
    }
}

- (id)init
{
    self = [super init];
    if (self) {
        _variablesDict = [[NSMutableDictionary alloc] init];
    }
    return self;
}

- (NSString *)valueForVariable:(NSString *)varName {
    NSString *val = [_variablesDict valueForKeyPath:varName];
    return val;
    return nil;
}

-(NSString *)description {
    return [NSString stringWithFormat:@"Current Variables: %@", _variablesDict];
}

@end
0
Chilly

Je recommanderais de regarder getResourceValue:forKey:error: . Le paramètre forKey sera y, je crois.

0
fbrereto