NSURL 为参数字符串中的键提取单个值
Posted
技术标签:
【中文标题】NSURL 为参数字符串中的键提取单个值【英文标题】:NSURL pull out a single value for a key in a parameter string 【发布时间】:2011-01-14 14:40:59 【问题描述】:我有一个 NSURL:
serverCall?x=a&y=b&z=c
获取 y 值的最快和最有效的方法是什么?
谢谢
【问题讨论】:
【参考方案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"]);
【讨论】:
你应该使用NSUTF8StringEncoding
而不是NSASCIIStringEncoding
,除非你讨厌不会说英语的人。
他是对的,你知道 Dave,尽管这是有关 URL 方案决定使用的编码问题。对于几乎所有的东西,那就是 UTF-8,很高兴
感谢您在 3 年前保持诚实 :)【参考方案2】:
更新:
自 2010 年撰写本文以来,Apple 似乎已为此目的发布了一套工具。请参阅下面的答案。
老派解决方案:
我知道你说“最快的方法”,但在我开始使用 NSScanner
进行测试后,我就停不下来了。虽然这不是最短的方法,但如果您打算大量使用该功能,它肯定很方便。我创建了一个URLParser
类,它使用NSScanner
获取这些变量。使用很简单:
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
执行此操作的类如下(*源文件在帖子底部):
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
*如果你不喜欢复制和粘贴,你可以下载源文件 - 我写了一篇关于 here 的快速博客文章。
【讨论】:
+1 太棒了!NSScanner
是一个我没玩过的课程,这看起来很有趣。我要说的唯一评论是不要调用方法getValue...
。这意味着(根据惯例)您将通过 out 参数返回值。 valueForVariable:
是正确的名称。
我之前也没有玩过NSScanner
,所以我认为这是一个很好的测试任务。至于方法名称,我也不喜欢它,但它是凌晨 2:00 并且想把事情结束:P 它已更新。
感谢这个可重用的类
您是否为此创建了任何开源存储库?和cocoapods一起?
不工作。 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.
【参考方案3】:
最快的是:
NSString* x = [url valueForQueryParameterKey:@"x"];
【讨论】:
【参考方案4】:您可以使用 Google Toolbox for Mac。 它向 NSString 添加了一个函数,用于将查询字符串转换为字典。
http://code.google.com/p/google-toolbox-for-mac/
它就像一个魅力
NSDictionary * d = [NSDictionary gtm_dictionaryWithHttpArgumentsString:[[request URL] query]];
【讨论】:
【参考方案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
【讨论】:
+1:我同意这比NSArray
更适合NSDictionary
。但是,如果您要使用此函数,请确保将此值分配给 ivar... 即 NSDictionary *paramsDict = [myURL dictionaryValue]
... 您不想一遍又一遍地构建此字典以获取每个参数的价值... ;P【参考方案6】:
我编写了一个简单的类别来扩展 NSString/NSURL,它可以让您单独提取 URL 查询参数或作为键/值对的字典:
https://github.com/nicklockwood/RequestUtils
【讨论】:
【参考方案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;
它会像这样返回字典:Key = value
【讨论】:
【参考方案8】:我一直在使用这个类别:https://github.com/carlj/NSURL-Parameters。
它小巧易用:
#import "NSURL+Parameters.h"
...
NSURL *url = [NSURL URLWithString:@"http://foo.bar.com?paramA=valueA¶mB=valueB"];
NSString *paramA = url[@"paramA"];
NSString *paramB = url[@"paramB"];
【讨论】:
【参考方案9】:为了更好的内存管理和效率,我稍微编辑了 Dimitris 的代码。此外,它适用于 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
【讨论】:
【参考方案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"])
【讨论】:
这应该是现在接受的答案:当前接受的答案已被取代。这种方法也不仅仅适用于 Swift。 Objective-C 也可以使用 NSURLComponents。它可从 ios 7 获得:nshipster.com/nsurl【参考方案11】:这里有这么多自定义 url 解析器,记住 NSURLComponents 是你的朋友!
这是一个示例,我为“页面”提取了一个 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];
“为什么要重新发明***!” - 聪明人
【讨论】:
其实我不明白为什么这个答案没有被标记为更正的答案。谢谢@anders。 @AlexKrzyżanowski,比赛迟到了:P 更紧凑一点:let pageNumber: Int? = Int(NSURLComponents(string: myURL.absoluteString ?? "")?.queryItems?.filter $0.name == "page" .first?.value ?? "NaN") +1 使用 NSURLComponents。 (已投票)它为你处理了很多事情。比自己做要好得多。 埃德温·维米尔和奈法利安布莱克。但是,感谢您的建议,虽然我的代码可能过于冗长,但可能可以优化并且当然可以压缩,但对于代码示例来说,尽可能清晰更重要。在专业环境中也应遵循同样的态度。您应该始终专注于编写不会让您的同事感到困惑的干净代码;如果您的代码一目了然不可读,这不是竞争,也不利于团队的生产力。可读性应该永远比代码的紧凑性更重要。【参考方案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)")
【讨论】:
很棒的扩展,写得很好,简单而且效果很好!【参考方案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;
【讨论】:
以上是关于NSURL 为参数字符串中的键提取单个值的主要内容,如果未能解决你的问题,请参考以下文章
在 Reporting Services 中为单个参数传递多个值