NSURL 提取参数字符串中键的单个值

NSURL pull out a single value for a key in a parameter string

提问人:Dave 提问时间:2/9/2010 最后编辑:Mike AbdullahDave 更新时间:12/6/2016 访问量:35299

问:

我有一个 NSURL:

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

获得 y 值的最快和最有效的方法是什么?

谢谢

nsurl

评论


答:

20赞 Dave DeLong 2/9/2010 #1

我很确定你必须自己解析它。但是,这还不错:

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

评论

8赞 Jakob Egger 4/2/2013
除非你讨厌非英语人士,否则你应该使用它。NSUTF8StringEncodingNSASCIIStringEncoding
0赞 Mike Abdullah 1/10/2014
他是对的,你知道戴夫,尽管这是相关 URL 方案决定使用的编码问题。对于几乎所有的东西,那就是 UTF-8,这已经足够了
79赞 Dimitris 2/9/2010 #2

更新:

自 2010 年撰写本文以来,Apple 似乎已经为此发布了一套工具。请参阅下面的答案。

老式解决方案:

好吧,我知道你说的是“最快的方法”,但在我开始做测试后,我就停不下来了。虽然这不是最短的方法,但如果您打算经常使用该功能,它肯定会很方便。我创建了一个类,该类使用 .使用方法很简单:NSScannerURLParserNSScanner

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

执行此操作的类如下(*文章底部的源文件):

网址:Präser.h

@interface URLParser : NSObject {
    NSArray *variables;
}

@property (nonatomic, retain) NSArray *variables;

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

@end

网址:Präser.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

*如果您不喜欢复制和粘贴,您可以下载源文件 - 我在这里写了一篇关于此的快速博客文章。

评论

4赞 Dave DeLong 2/9/2010
+1 真棒! 是我没怎么玩过的班级,看起来真的很有意思。我唯一要说的是不要调用该方法。这意味着(按照惯例)您将通过 out 参数返回值。 将是正确的名称。NSScannergetValue...valueForVariable:
0赞 Dimitris 2/9/2010
我以前也没有玩过,所以我认为这是一项不错的任务来测试它。至于方法名称,我也不喜欢它,但现在是凌晨 2:00,想总结一下:P它已更新。NSScanner
0赞 iOSAppDev 5/28/2013
感谢这个可重用的类
0赞 Janak Nirmal 7/25/2013
您是否为此创建了任何开源存储库?与可可足类动物一起?
0赞 Doug Smith 12/7/2013
不工作。 每次都崩溃并出现此错误:https://www.youtube.com/watch?feature=player_embedded&v=Bci1eZFoyEg*** Terminating app due to uncaught exception 'NSUnknownKeyException', reason: '[<DDURLParser 0x8d37bf0> valueForUndefinedKey:]: this class is not key value coding-compliant for the key v.
-2赞 Malcolm Hall 8/1/2010 #3

最快的是:

NSString* x = [url valueForQueryParameterKey:@"x"];
4赞 ventayol 11/9/2011 #4

您可以使用 Google Toolbox for Mac。 它向 NSString 添加了一个函数,用于将查询字符串转换为字典。

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

它就像一个魅力

        NSDictionary * d = [NSDictionary gtm_dictionaryWithHttpArgumentsString:[[request URL] query]];
2赞 odyth 7/27/2012 #5

我使用基于@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

评论

0赞 JRG-Developer 4/3/2013
+1:我同意这比 .但是,如果您要使用此函数,请确保将此值分配给 ivar...即......你不想一遍又一遍地构建这个字典来获取每个参数的值...... ;PNSDictionaryNSArrayNSDictionary *paramsDict = [myURL dictionaryValue]
3赞 Nick Lockwood 9/6/2012 #6

我编写了一个简单的类别来扩展 NSString/NSURL,它允许您单独提取 URL 查询参数或作为键/值对的字典:

https://github.com/nicklockwood/RequestUtils

0赞 tryp 2/28/2013 #7

你可以做这很容易:

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

它像它一样返回字典:键 = 值

10赞 Troy 1/10/2014 #8

我一直在使用这个类别:https://github.com/carlj/NSURL-Parameters

它体积小且易于使用:

#import "NSURL+Parameters.h"
...
NSURL *url = [NSURL URLWithString:@"http://foo.bar.com?paramA=valueA&paramB=valueB"];
NSString *paramA = url[@"paramA"];
NSString *paramB = url[@"paramB"];
0赞 Chilly 4/7/2014 #9

我稍微编辑了 Dimitris 的代码,以获得更好的内存管理和效率。此外,它还适用于 ARC。

网址:Präser.h

@interface URLParser : NSObject

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

@end

网址:Präser.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
12赞 leafcutter 2/5/2015 #10

在 Swift 中,你可以使用 NSURLComponents 将 NSURL 的查询字符串解析为 [AnyObject]。

然后,您可以从中创建字典(或直接访问项目)以获取键/值对。例如,这是我用来解析 NSURL 变量 url 的方法:

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"])

评论

1赞 SeanR 5/12/2015
这应该是现在接受的答案:当前接受的答案已被取代。这种方法也不仅适用于 Swift;Objective-C 也可以使用 NSURLComponents。它可从 iOS 7 获得:nshipster.com/nsurl
73赞 anders 3/29/2015 #11

这里有这么多自定义 url 解析器,请记住 NSURLComponents 是你的朋友!

这是一个示例,我为“page”提取了一个 url 编码参数

迅速

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

Objective-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];
}

“为什么要重新发明轮子!”

评论

3赞 Alexander Perechnev 5/27/2016
实际上,我不明白为什么这个答案没有被标记为更正的答案。谢谢@anders。
1赞 anders 5/28/2016
@AlexKrzyżanowski,迟到了:P
1赞 Edwin Vermeer 9/30/2016
更紧凑一点:let pageNumber: Int?= Int(NSURLComponents(string: myURL.absoluteString ??"")?.queryItems?。filter { $0.name == “page” }.first?.价值??“NaN”)
0赞 Duncan C 10/28/2016
使用 NSURLComponents 时为 +1。(已投票)它为你处理了很多东西。比自己动手要好得多。
1赞 anders 12/17/2016
埃德温·维米尔(Edwin Vermeer)和尼法里安布莱克(nefarianblack)。但是,感谢您的建议,虽然我的代码可能过于冗长,但可以优化并且肯定可以压缩,但更重要的是代码示例尽可能清晰。在专业环境中也应遵循同样的态度。您应该始终专注于编写不会让您的同事感到困惑的干净代码;它不是竞争,如果你的代码在短时间内无法阅读,它对团队的生产力没有好处。可读性应该始终比代码的紧凑性更重要。
4赞 Albert Bori 5/28/2016 #12

下面是一个 Swift 2.0 扩展,它提供了对参数的简单访问:

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

用法示例:

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

评论

0赞 Unome 6/7/2016
很棒的扩展,写得很好,简单,效果很好!
1赞 IanS 7/1/2016 #13

当前所有答案都是特定于版本的,或者是不必要的浪费。如果您只需要一个值,为什么要创建字典?

这是一个支持所有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;
}