我有一个像myApp://action/1?parameter=2&secondparameter=3
通过属性查询,我得到了URL
parameter=2&secondparameter=3
有什么方法可以轻松地将其放在NSDictionary
或Array
中吗?
很多
答案 0 :(得分:142)
您可以在URLComponents
中使用queryItems
。
当你获得这个属性的值时,NSURLComponents类会解析查询字符串并返回一个NSURLQueryItem对象数组,每个对象代表一个键值对,按照它们在原始查询字符串中出现的顺序。 / p>
let url = "http://example.com?param1=value1¶m2=param2"
let queryItems = URLComponents(string: url)?.queryItems
let param1 = queryItems?.filter({$0.name == "param1"}).first
print(param1?.value)
NSURLComponents *urlComponents = [NSURLComponents componentsWithURL:url
resolvingAgainstBaseURL:NO];
NSArray *queryItems = urlComponents.queryItems;
NSString *param1 = [self valueForKey:@"param1"
fromQueryItems:queryItems];
NSLog(@"%@", param1);
…
- (NSString *)valueForKey:(NSString *)key
fromQueryItems:(NSArray *)queryItems
{
NSPredicate *predicate = [NSPredicate predicateWithFormat:@"name=%@", key];
NSURLQueryItem *queryItem = [[queryItems
filteredArrayUsingPredicate:predicate]
firstObject];
return queryItem.value;
}
答案 1 :(得分:55)
我有理由为这种可能派上用场的行为编写一些扩展。首先是标题:
#import <Foundation/Foundation.h>
@interface NSString (XQueryComponents)
- (NSString *)stringByDecodingURLFormat;
- (NSString *)stringByEncodingURLFormat;
- (NSMutableDictionary *)dictionaryFromQueryComponents;
@end
@interface NSURL (XQueryComponents)
- (NSMutableDictionary *)queryComponents;
@end
@interface NSDictionary (XQueryComponents)
- (NSString *)stringFromQueryComponents;
@end
这些方法扩展了NSString,NSURL和NSDictionary,允许您在包含结果的查询组件字符串和字典对象之间进行转换。
现在相关的.m代码:
#import "XQueryComponents.h"
@implementation NSString (XQueryComponents)
- (NSString *)stringByDecodingURLFormat
{
NSString *result = [self stringByReplacingOccurrencesOfString:@"+" withString:@" "];
result = [result stringByReplacingPercentEscapesUsingEncoding:NSUTF8StringEncoding];
return result;
}
- (NSString *)stringByEncodingURLFormat
{
NSString *result = [self stringByReplacingOccurrencesOfString:@" " withString:@"+"];
result = [result stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding];
return result;
}
- (NSMutableDictionary *)dictionaryFromQueryComponents
{
NSMutableDictionary *queryComponents = [NSMutableDictionary dictionary];
for(NSString *keyValuePairString in [self componentsSeparatedByString:@"&"])
{
NSArray *keyValuePairArray = [keyValuePairString componentsSeparatedByString:@"="];
if ([keyValuePairArray count] < 2) continue; // Verify that there is at least one key, and at least one value. Ignore extra = signs
NSString *key = [[keyValuePairArray objectAtIndex:0] stringByDecodingURLFormat];
NSString *value = [[keyValuePairArray objectAtIndex:1] stringByDecodingURLFormat];
NSMutableArray *results = [queryComponents objectForKey:key]; // URL spec says that multiple values are allowed per key
if(!results) // First object
{
results = [NSMutableArray arrayWithCapacity:1];
[queryComponents setObject:results forKey:key];
}
[results addObject:value];
}
return queryComponents;
}
@end
@implementation NSURL (XQueryComponents)
- (NSMutableDictionary *)queryComponents
{
return [[self query] dictionaryFromQueryComponents];
}
@end
@implementation NSDictionary (XQueryComponents)
- (NSString *)stringFromQueryComponents
{
NSString *result = nil;
for(__strong NSString *key in [self allKeys])
{
key = [key stringByEncodingURLFormat];
NSArray *allValues = [self objectForKey:key];
if([allValues isKindOfClass:[NSArray class]])
for(__strong NSString *value in allValues)
{
value = [[value description] stringByEncodingURLFormat];
if(!result)
result = [NSString stringWithFormat:@"%@=%@",key,value];
else
result = [result stringByAppendingFormat:@"&%@=%@",key,value];
}
else {
NSString *value = [[allValues description] stringByEncodingURLFormat];
if(!result)
result = [NSString stringWithFormat:@"%@=%@",key,value];
else
result = [result stringByAppendingFormat:@"&%@=%@",key,value];
}
}
return result;
}
@end
答案 2 :(得分:54)
类似的东西:
NSMutableDictionary *params = [[NSMutableDictionary alloc] init];
for (NSString *param in [url componentsSeparatedByString:@"&"]) {
NSArray *elts = [param componentsSeparatedByString:@"="];
if([elts count] < 2) continue;
[params setObject:[elts lastObject] forKey:[elts firstObject]];
}
注意:这是示例代码。不管理所有错误情况。
答案 3 :(得分:13)
试试这个;)!
NSString *query = @"parameter=2&secondparameter=3"; // replace this with [url query];
NSArray *components = [query componentsSeparatedByString:@"&"];
NSMutableDictionary *parameters = [[NSMutableDictionary alloc] init];
for (NSString *component in components) {
NSArray *subcomponents = [component componentsSeparatedByString:@"="];
[parameters setObject:[[subcomponents objectAtIndex:1] stringByReplacingPercentEscapesUsingEncoding:NSUTF8StringEncoding]
forKey:[[subcomponents objectAtIndex:0] stringByReplacingPercentEscapesUsingEncoding:NSUTF8StringEncoding]];
}
答案 4 :(得分:9)
所有以前的帖子都没有正确进行网址编码。我会建议以下方法:
+(NSString*)concatenateQuery:(NSDictionary*)parameters {
if([parameters count]==0) return nil;
NSMutableString* query = [NSMutableString string];
for(NSString* parameter in [parameters allKeys])
[query appendFormat:@"&%@=%@",[parameter stringByAddingPercentEncodingWithAllowedCharacters:NSCharacterSet.URLQueryAllowedCharacterSet],[[parameters objectForKey:parameter] stringByAddingPercentEncodingWithAllowedCharacters:NSCharacterSet.URLQueryAllowedCharacterSet]];
return [[query substringFromIndex:1] copy];
}
+(NSDictionary*)splitQuery:(NSString*)query {
if([query length]==0) return nil;
NSMutableDictionary* parameters = [NSMutableDictionary dictionary];
for(NSString* parameter in [query componentsSeparatedByString:@"&"]) {
NSRange range = [parameter rangeOfString:@"="];
if(range.location!=NSNotFound)
[parameters setObject:[[parameter substringFromIndex:range.location+range.length] stringByReplacingPercentEscapesUsingEncoding:NSUTF8StringEncoding] forKey:[[parameter substringToIndex:range.location] stringByReplacingPercentEscapesUsingEncoding:NSUTF8StringEncoding]];
else [parameters setObject:[[NSString alloc] init] forKey:[parameter stringByReplacingPercentEscapesUsingEncoding:NSUTF8StringEncoding]];
}
return [parameters copy];
}
答案 5 :(得分:7)
这是swift中的扩展名:
extension NSURL{
func queryParams() -> [String:AnyObject] {
var info : [String:AnyObject] = [String:AnyObject]()
if let queryString = self.query{
for parameter in queryString.componentsSeparatedByString("&"){
let parts = parameter.componentsSeparatedByString("=")
if parts.count > 1{
let key = (parts[0] as String).stringByReplacingPercentEscapesUsingEncoding(NSUTF8StringEncoding)
let value = (parts[1] as String).stringByReplacingPercentEscapesUsingEncoding(NSUTF8StringEncoding)
if key != nil && value != nil{
info[key!] = value
}
}
}
}
return info
}
}
答案 6 :(得分:7)
根据已经very clean answer of Onato,我在Swift中为NSURL写了一个扩展,你可以在这里获得一个查询参数:
e.g。该URL包含param = some_value
对let queryItem = url.queryItemForKey("param")
let value = queryItem.value // would get String "someValue"
扩展名如下:
extension NSURL {
var allQueryItems: [NSURLQueryItem] {
get {
let components = NSURLComponents(URL: self, resolvingAgainstBaseURL: false)!
let allQueryItems = components.queryItems!
return allQueryItems as [NSURLQueryItem]
}
}
func queryItemForKey(key: String) -> NSURLQueryItem? {
let predicate = NSPredicate(format: "name=%@", key)!
return (allQueryItems as NSArray).filteredArrayUsingPredicate(predicate).first as? NSURLQueryItem
}
}
答案 7 :(得分:5)
对于那些使用 Bolts Framework 的人,您可以使用:
NSDictionary *parameters = [BFURL URLWithURL:yourURL].inputQueryParameters;
记得导入:
#import <Bolts/BFURL.h>
如果您的项目中碰巧有 Facebook SDK ,那么您还有螺栓。 Facebook正在使用这个框架作为依赖。
答案 8 :(得分:3)
Swift 2.1
Oneliner:
"p1=v1&p2=v2".componentsSeparatedByString("&").map {
$0.componentsSeparatedByString("=")
}.reduce([:]) {
(var dict: [String:String], p) in
dict[p[0]] = p[1]
return dict
}
// ["p1": "v1", "p2": "v2"]
用作NSURL的扩展程序:
extension NSURL {
/**
* URL query string as dictionary. Empty dictionary if query string is nil.
*/
public var queryValues : [String:String] {
get {
if let q = self.query {
return q.componentsSeparatedByString("&").map {
$0.componentsSeparatedByString("=")
}.reduce([:]) {
(var dict: [String:String], p) in
dict[p[0]] = p[1]
return dict
}
} else {
return [:]
}
}
}
}
示例:
let url = NSURL(string: "http://example.com?p1=v1&p2=v2")!
let queryDict = url.queryValues
// ["p1": "v1", "p2": "v2"]
请注意,如果使用OS X 10.10或iOS 8(或更高版本),最好使用NSURLComponents
和queryItems
属性,并直接从NSURLQueryItems
创建字典。
以下是基于NSURLComponents
的{{1}}扩展解决方案:
NSURL
NSURL扩展的脚注是,Swift实际上可以为属性提供与现有字符串属性相同的名称 - extension NSURL {
/// URL query string as a dictionary. Empty dictionary if query string is nil.
public var queryValues : [String:String] {
get {
guard let components = NSURLComponents(URL: self, resolvingAgainstBaseURL: false) else {
return [:]
}
guard let queryItems = components.queryItems else {
return [:]
}
var result:[String:String] = [:]
for q in queryItems {
result[q.name] = q.value
}
return result
}
}
}
。直到我尝试它才知道,但是Swift中的多态性只允许你在返回类型上有所不同。因此,如果扩展的NSURL属性为query
则可行。我没有在示例中使用它,因为我发现它有点疯狂,但它确实有用......
答案 9 :(得分:3)
目前处理网址的首选方式是NSURLComponents
。特别是queryItems
属性,它返回NSDictionary
个参数。
如果你想要+(NSDictionary<NSString *, NSString *>*)queryParamsFromURL:(NSURL*)url
{
NSURLComponents* urlComponents = [NSURLComponents componentsWithURL:url resolvingAgainstBaseURL:NO];
NSMutableDictionary<NSString *, NSString *>* queryParams = [NSMutableDictionary<NSString *, NSString *> new];
for (NSURLQueryItem* queryItem in [urlComponents queryItems])
{
if (queryItem.value == nil)
{
continue;
}
[queryParams setObject:queryItem.value forKey:queryItem.name];
}
return queryParams;
}
中的参数,这里有一个方法:
queryItems
警告:URL可以有重复的参数,但字典只包含任何重复参数的最后一个值。如果不合需要,请直接使用{
"query": {
"bool": {
"must": [
{
"terms": {
"field1": [ "a", "b", "c" ]
}
},
{
"terms": {
"field2": [ "d", "e", "f" ]
}
},
{
"terms": {
"field3": [ "g", "h", "i" ]
}
}
]
}
}
}
数组。
答案 10 :(得分:2)
我在麻省理工学院发表了一个简单的课程:
https://github.com/anegmawad/URLQueryToCocoa
有了它,你可以在查询中拥有数组和对象,这些数组和对象被收集并粘合在一起
例如
users[0][firstName]=Amin&users[0][lastName]=Negm&name=Devs&users[1][lastName]=Kienle&users[1][firstName]=Christian
将成为:
@{
name : @"Devs",
users :
@[
@{
firstName = @"Amin",
lastName = @"Negm"
},
@{
firstName = @"Christian",
lastName = @"Kienle"
}
]
}
您可以将其视为NSJSONSerializer
的网址查询对象。
答案 11 :(得分:1)
看起来您正在使用它来处理来自其他iOS应用程序的传入数据。如果是这样,这就是我用于同一目的的。
初始通话(例如在外部申请中):
UIApplication *application = [UIApplication sharedApplication];
NSURL *url = [NSURL URLWithString:@"myApp://action/1?parameter=2&secondparameter=3"];
if ([application canOpenURL:url]) {
[application openURL:url];
NSLog(@"myApp is installed");
} else {
NSLog(@"myApp is not installed");
}
从NSURL中提取QueryString数据并保存为NSDictionary的方法:
-(NSDictionary *) getNSDictionaryFromQueryString:(NSURL *)url {
NSMutableDictionary *result = [[NSMutableDictionary alloc] init];
NSRange needle = [url.absoluteString rangeOfString:@"?" options:NSCaseInsensitiveSearch];
NSString *data = nil;
if(needle.location != NSNotFound) {
NSUInteger start = needle.location + 1;
NSUInteger end = [url.absoluteString length] - start;
data = [url.absoluteString substringWithRange:NSMakeRange(start, end)];
}
for (NSString *param in [data componentsSeparatedByString:@"&"]) {
NSArray *keyvalue = [param componentsSeparatedByString:@"="];
if([keyvalue count] == 2){
[result setObject:[keyvalue objectAtIndex:1] forKey:[keyvalue objectAtIndex:0]];
}
}
return result;
}
用法:
NSDictionary *result = [self getNSDictionaryFromQueryString:url];
答案 12 :(得分:0)
这个类是解析url的好方法。
.h文件
@interface URLParser : NSObject {
NSArray *variables;
}
@property (nonatomic, retain) NSArray *variables;
- (id)initWithURLString:(NSString *)url;
- (NSString *)valueForVariable:(NSString *)varName;
@end
.m文件
#import "URLParser.h"
@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;
}
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;
}
@end
答案 13 :(得分:0)
Hendrik在这个问题中为扩展写了一个很好的例子,但是我不得不重新编写它以不使用任何objective-c库方法。在swift中使用NSArray
不是正确的方法。
这是结果,所有快速,更安全。使用示例将使用Swift 1.2减少代码行。
public extension NSURL {
/*
Set an array with all the query items
*/
var allQueryItems: [NSURLQueryItem] {
get {
let components = NSURLComponents(URL: self, resolvingAgainstBaseURL: false)!
if let allQueryItems = components.queryItems {
return allQueryItems as [NSURLQueryItem]
} else {
return []
}
}
}
/**
Get a query item form the URL query
:param: key The parameter to fetch from the URL query
:returns: `NSURLQueryItem` the query item
*/
public func queryItemForKey(key: String) -> NSURLQueryItem? {
let filteredArray = filter(allQueryItems) { $0.name == key }
if filteredArray.count > 0 {
return filteredArray.first
} else {
return nil
}
}
}
用法:
let queryItem = url.queryItemForKey("myItem")
或者,更详细的用法:
if let url = NSURL(string: "http://www.domain.com/?myItem=something") {
if let queryItem = url.queryItemForKey("myItem") {
if let value = queryItem.value {
println("The value of 'myItem' is: \(value)")
}
}
}
答案 14 :(得分:0)
试试这个:
-(NSDictionary *)getUrlParameters:(NSString *)url{
NSArray *justParamsArr = [url componentsSeparatedByString:@"?"];
url = [justParamsArr lastObject];
NSMutableDictionary *params = [[NSMutableDictionary alloc] init];
for (NSString *param in [url componentsSeparatedByString:@"&"]) {
NSArray *elts = [param componentsSeparatedByString:@"="];
if([elts count] < 2) continue;
[params setObject:[elts lastObject] forKey:[elts firstObject]];
}
return params;
}
答案 15 :(得分:0)
完全紧凑的方法:
func stringParamsToDict(query: String) -> [String: String] {
let params = query.components(separatedBy: "&").map {
$0.components(separatedBy: "=")
}.reduce(into: [String: String]()) { dict, pair in
if pair.count == 2 {
dict[pair[0]] = pair[1]
}
}
return params
}
答案 16 :(得分:-5)
最强大的解决方案,如果您使用网址将数据从网络应用程序传递到手机,并且您想传递数组,数字,字符串,......
JSON使用PHP编码您的对象
header("Location: myAppAction://".urlencode(json_encode($YOUROBJECT)));
JSON解码iOS中的结果
NSData *data = [[[request URL] host] dataUsingEncoding:NSUTF8StringEncoding];
NSDictionary *packed = [NSJSONSerialization JSONObjectWithData:data options:0 error:nil];