У меня есть NSURL:
вызов сервера?x=a&y=b&z=c
Каков самый быстрый и эффективный способ получить значение y?
Спасибо
У меня есть NSURL:
вызов сервера?x=a&y=b&z=c
Каков самый быстрый и эффективный способ получить значение y?
Спасибо
ОБНОВЛЕНИЕ:
Похоже, что с 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
*если вам не нравится копировать и вставлять, вы можете просто загрузить исходные файлы - я сделал короткую запись в блоге об этом здесь.
NSScanner
— это класс, с которым я мало играл, и он выглядит очень интересно. Единственный комментарий, который я хотел бы сказать, это не вызывать метод getValue...
. Это подразумевает (согласно соглашению), что вы собираетесь возвращать значение через выходной параметр. valueForVariable:
было бы правильным именем.
- person Dave DeLong; 09.02.2010
NSScanner
, поэтому решил, что это хорошая задача, чтобы протестировать его. Что касается названия метода, оно мне тоже не понравилось, но было 2 часа ночи, и я хотел подвести итоги: P Оно обновлено.
- person Dimitris; 09.02.2010
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.
- person Doug Smith; 06.12.2013
Здесь так много настраиваемых парсеров 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)")
Цель-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];
}
"Зачем изобретать велосипед!" - Кто-то умный
if let queryItems = NSURLComponents(url: url, resolvingAgainstBaseURL: true)?.queryItems, let code = queryItems.filter({ $0.name == "page" }).reduce(nil, { $1 })?.value { /*Blah blah, do stuff with code variable here/* }
Это не совсем так читабельно, но вы можете использовать именованные переменные вместо анонимных переменных, если хотите сделать его немного более разборчивым. Я просто подумал, что это было полезно, так что вы можете получить результат в if-let.
- person stuckj; 30.10.2018
Я почти уверен, что вы должны разобрать его самостоятельно. Тем не менее, это не так уж плохо:
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
, если только вы не ненавидите людей, не говорящих по-английски.
- person Jakob Egger; 02.04.2013
В Swift вы можете использовать NSURLComponents для анализа строки запроса NSURL в [AnyObject].
Затем вы можете создать из него словарь (или получить доступ к элементам напрямую), чтобы получить пары ключ/значение. В качестве примера это то, что я использую для анализа URL-адреса переменной 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"])
Я использовал эту категорию: 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"];
Вы можете использовать Google Toolbox для Mac. Он добавляет в NSString функцию для преобразования строки запроса в словарь.
http://code.google.com/p/google-toolbox-for-mac/
Работает как часы
NSDictionary * d = [NSDictionary gtm_dictionaryWithHttpArgumentsString:[[request URL] query]];
Вот расширение 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)")
}
Я написал простую категорию для расширения NSString/NSURL, которая позволяет извлекать параметры запроса URL по отдельности или в виде словаря пар ключ/значение:
https://github.com/nicklockwood/RequestUtils
Я сделал это, используя метод категории, основанный на решении @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
NSDictionary
, чем для NSArray
. Однако, если вы собираетесь использовать эту функцию, убедитесь, что вы присваиваете это значение ivar... т.е. NSDictionary *paramsDict = [myURL dictionaryValue]
... вы не хотите создавать этот словарь снова и снова, чтобы получить значение каждого параметра. .. ;П
- person JRG-Developer; 02.04.2013
Все текущие ответы зависят от версии или излишне расточительны. Зачем создавать словарь, если вам нужно только одно значение?
Вот простой ответ, который поддерживает все версии 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;
}
Вы можете сделать это легко:
- (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
Я немного отредактировал код Димитриса для лучшего управления памятью и повышения эффективности. Кроме того, он работает в 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
Самый быстрый это:
NSString* x = [url valueForQueryParameterKey:@"x"];