Лучший способ разобрать строку URL, чтобы получить значения для ключей? - PullRequest
71 голосов
/ 06 января 2012

Мне нужно проанализировать строку URL, например, такую:

&ad_eurl=http://www.youtube.com/video/4bL4FI1Gz6s&hl=it_IT&iv_logging_level=3&ad_flags=0&endscreen_module=http://s.ytimg.com/yt/swfbin/endscreen-vfl6o3XZn.swf&cid=241&cust_gender=1&avg_rating=4.82280613104

Мне нужно разбить строку NSString на части, такие как cid=241 и &avg_rating=4.82280613104. Я делаю это с substringWithRange:, но значения возвращаются в случайном порядке, так что все портится. Есть ли какой-нибудь класс, который позволяет легко анализировать, где вы можете конвертировать его в NSDictionary, чтобы иметь возможность прочитать значение для ключа (например, ValueForKey: cid должно возвращать 241). Или есть просто более простой способ его анализа, чем использование NSMakeRange для получения подстроки?

Ответы [ 15 ]

155 голосов
/ 16 октября 2014

Я также ответил на это https://stackoverflow.com/a/26406478/215748.

Вы можете использовать queryItems в URLComponents.

Когда вы получаете значение этого свойства, класс NSURLComponents анализирует строку запроса и возвращает массив объектов NSURLQueryItem, каждый из которых представляет одну пару ключ-значение, в том порядке, в котором они появляются в исходной строке запроса.

Swift 3

let url = "http://example.com?param1=value1&param2=param2"
let queryItems = URLComponents(string: url)?.queryItems
let param1 = queryItems?.filter({$0.name == "param1"}).first
print(param1?.value)

Swift 2.3

Используйте NSURLComponents вместо URLComponents.

Цель C

Использование NSURLComponents.

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;
}
115 голосов
/ 06 января 2012

изменить (июнь 2018): этот ответ лучше .Apple добавила NSURLComponents в iOS 7 .

Я бы создал словарь, получил бы массив пар ключ / значение с помощью

NSMutableDictionary *queryStringDictionary = [[NSMutableDictionary alloc] init];
NSArray *urlComponents = [urlString componentsSeparatedByString:@"&"];

Затем заполнил словарь:

for (NSString *keyValuePair in urlComponents)
{
    NSArray *pairComponents = [keyValuePair componentsSeparatedByString:@"="];
    NSString *key = [[pairComponents firstObject] stringByRemovingPercentEncoding];
    NSString *value = [[pairComponents lastObject] stringByRemovingPercentEncoding];

    [queryStringDictionary setObject:value forKey:key];
}

Затем вы можете запросить с помощью

[queryStringDictionary objectForKey:@"ad_eurl"];

Это не проверено, и вам, вероятно, следует провести еще несколько тестов ошибок.

46 голосов
/ 22 ноября 2012

Я немного опоздал, но ответы, предоставленные до сих пор, не работали так, как мне было нужно. Вы можете использовать этот фрагмент кода:

NSMutableDictionary *queryStrings = [[NSMutableDictionary alloc] init];
for (NSString *qs in [url.query componentsSeparatedByString:@"&"]) {
    // Get the parameter name
    NSString *key = [[qs componentsSeparatedByString:@"="] objectAtIndex:0];
    // Get the parameter value
    NSString *value = [[qs componentsSeparatedByString:@"="] objectAtIndex:1];
    value = [value stringByReplacingOccurrencesOfString:@"+" withString:@" "];
    value = [value stringByReplacingPercentEscapesUsingEncoding:NSUTF8StringEncoding];

    queryStrings[key] = value;
}

Где url - это URL, который вы хотите проанализировать. У вас есть все экранированные строки запроса в изменяемом словаре queryStrings.

РЕДАКТИРОВАТЬ : Swift версия:

var queryStrings = [String: String]()
if let query = url.query {
    for qs in query.componentsSeparatedByString("&") {
        // Get the parameter name
        let key = qs.componentsSeparatedByString("=")[0]
        // Get the parameter value
        var value = qs.componentsSeparatedByString("=")[1]
        value = value.stringByReplacingOccurrencesOfString("+", withString: " ")
        value = value.stringByReplacingPercentEscapesUsingEncoding(NSUTF8StringEncoding)!

        queryStrings[key] = value
    }
}
9 голосов
/ 13 октября 2015

Для iOS8 и выше с использованием NSURLComponents:

+(NSDictionary<NSString *, NSString *> *)queryParametersFromURL:(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;
}

Для iOS 8 ниже:

+(NSDictionary<NSString *, NSString *> *)queryParametersFromURL:(NSURL *)url    
    NSMutableDictionary<NSString *, NSString *> * parameters = [NSMutableDictionary<NSString *, NSString *> new];
    [self enumerateKeyValuePairsFromQueryString:url.query completionblock:^(NSString *key, NSString *value) {
        parameters[key] = value;
    }];
    return parameters.copy;
}

- (void)enumerateKeyValuePairsFromQueryString:(NSString *)queryString completionBlock:(void (^) (NSString *key, NSString *value))block {
    if (queryString.length == 0) {
        return;
    }
    NSArray *keyValuePairs = [queryString componentsSeparatedByString:@"&"];
    for (NSString *pair in keyValuePairs) {
        NSRange range = [pair rangeOfString:@"="];
        NSString *key = nil;
        NSString *value = nil;

        if (range.location == NSNotFound) {
            key = pair;
            value = @"";
        }
        else {
            key = [pair substringToIndex:range.location];
            value = [pair substringFromIndex:(range.location + range.length)];
        }

        key = [self decodedStringFromString:key];
        key = key ?: @"";

        value = [self decodedStringFromString:value];
        value = value ?: @"";

        block(key, value);
    }
}

+ (NSString *)decodedStringFromString:(NSString *)string {
    NSString *input = shouldDecodePlusSymbols ? [string stringByReplacingOccurrencesOfString:@"+" withString:@" " options:NSLiteralSearch range:NSMakeRange(0, string.length)] : string;
    return [input stringByReplacingPercentEscapesUsingEncoding:NSUTF8StringEncoding];
}
6 голосов
/ 17 октября 2014

Если вы хотите сделать то же самое в swift, вы можете использовать расширение.

extension NSURL {
    func queryDictionary() -> [String:String] {
        let components = self.query?.componentsSeparatedByString("&")
        var dictionary = [String:String]()

        for pairs in components ?? [] {
            let pair = pairs.componentsSeparatedByString("=")
            if pair.count == 2 {
                dictionary[pair[0]] = pair[1]
            }
        }

        return dictionary
    }
}
4 голосов
/ 21 ноября 2014

Если вы используете NSURLComponents, то следующее краткое расширение также поможет:

extension NSURLComponents {

    func getQueryStringParameter(name: String) -> String? {
        return (self.queryItems? as [NSURLQueryItem])
            .filter({ (item) in item.name == name }).first?
            .value()
    }

}
3 голосов
/ 18 августа 2016

Начиная с iOS 8, вы можете напрямую использовать свойства name и value для NSURLQueryItem.

Пример, как проанализировать URL и получить конкретные значения для ключа в разобранном видепары.

NSURLComponents *urlComponents = [NSURLComponents componentsWithURL:@"someURL" resolvingAgainstBaseURL:false];
NSArray *queryItems = urlComponents.queryItems;
NSMutableArray *someIDs = [NSMutableArray new];
for (NSURLQueryItem *item in queryItems) {
    if ([item.name isEqualToString:@"someKey"]) {
        [someIDs addObject:item.value];
    }
}
NSLog(@"%@", someIDs);
3 голосов
/ 02 августа 2013

Этот код работает в трех случаях

1. http://www.youtube.com/watch?v=VWsl7C-y7EI&feature=youtu.be 2. http://youtu.be/lOvcFqQyaDY
3. http://www.youtube.com/watch?v=VWsl7C-y7EI

NSArray *arr = [youtubeurl componentsSeparatedByString:@"v="];
 NSString *youtubeID;
if([arr count]>0)
{
    if([arr count]==1){
        youtubeID= [[youtubeurl componentsSeparatedByString:@"/"] lastObject];

    }
    else{
        NSArray *urlComponents = [[arr objectAtIndex:1] componentsSeparatedByString:@"&"];
        youtubeID=[urlComponents objectAtIndex:0];
    }
}
3 голосов
/ 06 января 2012
-(NSArray *)getDataOfQueryString:(NSString *)url{
    NSArray *strURLParse = [url componentsSeparatedByString:@"?"];
    NSMutableArray *arrQueryStringData = [[NSMutableArray alloc] init];
    if ([strURLParse count] < 2) {
        return arrQueryStringData;
    }
    NSArray *arrQueryString = [[strURLParse objectAtIndex:1] componentsSeparatedByString:@"&"];

    for (int i=0; i < [arrQueryString count]; i++) {
        NSMutableDictionary *dicQueryStringElement = [[NSMutableDictionary alloc]init];
        NSArray *arrElement = [[arrQueryString objectAtIndex:i] componentsSeparatedByString:@"="];
        if ([arrElement count] == 2) {
            [dicQueryStringElement setObject:[arrElement objectAtIndex:1] forKey:[arrElement objectAtIndex:0]];
        }
        [arrQueryStringData addObject:dicQueryStringElement];
    }

    return arrQueryStringData; 
}

Вы эту функцию просто передаете URL, и вы получите все элементы строки запроса.

2 голосов
/ 15 марта 2017

Позднее решение этой проблемы в виде расширения Swift 3 на URL

extension URL {

  func value(for paramater: String) -> String? {

    let queryItems = URLComponents(string: self.absoluteString)?.queryItems
    let queryItem = queryItems?.filter({$0.name == paramater}).first
    let value = queryItem?.value

    return value
  }

}

gist

...