कुंजी के लिए मान प्राप्त करने के लिए URL स्ट्रिंग को पार्स करने का सबसे अच्छा तरीका है?


81

मुझे इस तरह एक 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:लेकिन मान एक यादृच्छिक क्रम में लौटते हैं, ताकि यह गड़बड़ हो जाए। क्या कोई ऐसा वर्ग है जो आसान पार्सिंग की अनुमति देता है जहां आप मूल रूप से इसे एक कुंजी के लिए मूल्य पढ़ने में सक्षम होने के लिए एनएसडीआर में परिवर्तित कर सकते हैं (उदाहरण के लिए ValueForKey: cidवापसी चाहिए 241)। या वहाँ एक और आसान तरीका है NSMakeRangeएक विकल्प पाने के लिए उपयोग करने की तुलना में इसे पार्स करने के लिए है?

जवाबों:


122

edit (June 2018): यह उत्तर बेहतर है । एप्पल जोड़ा NSURLComponentsआईओएस 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"];

यह अप्रयुक्त है, और आपको संभवतः कुछ और त्रुटि परीक्षण करना चाहिए।


13
यह घटकों को URL-डीकोडिंग नहीं है। यह objectAtIndex: 1 करने से पहले युग्मकपार्टर्स एरे पर बाउंड चेकिंग भी नहीं कर रहा है: (क्या होगा अगर इंडेक्स 1 पर कोई ऑब्जेक्ट नहीं है?)।
यतनथोरजोश

8
क्वेरी स्ट्रिंग में मान से एक कुंजी को विभाजित करने के लिए "ComponentsSeparatedByString" का उपयोग करना सही नहीं है। "=" मूल्यों में अक्सर शामिल होता है (जैसे बेस 64 एन्कोडेड टोकन)।
डोपलिप

1
थोड़ा अनुकूलन: NSArray *urlComponents = [urlString componentsSeparatedByString:@"&"]; NSMutableDictionary *queryStringDictionary = [[NSMutableDictionary alloc] initWithCapacity: urlComponents.count];
अडंको

3
यदि किसी भी मान में "=" अक्षर समाहित है, तो यह पॉप्युलेट लॉजिक को तोड़ देता है। आप कोड का हिस्सा बदल सकते हैंNSRange range = [keyValuePair rangeOfString:@"="]; NSString *key = [keyValuePair substringToIndex:range.location]; NSString *value = [keyValuePair substringFromIndex:range.location+1];
रेनाटो सिल्वा दास नेव्स

1
यह पहला आइटम नहीं मिलता है।
कीथ एडलर

167

मैंने इसका जवाब https://stackoverflow.com/a/26406478/215748 पर भी दिया ।

आप उपयोग कर सकते हैं queryItemsमें URLComponents

जब आप इस गुण का मान प्राप्त करते हैं, तो NSURLCompords वर्ग क्वेरी स्ट्रिंग को पार्स करता है और NSURLQueryItem ऑब्जेक्ट्स की एक सरणी देता है, जिनमें से प्रत्येक एक एकल कुंजी-मूल्य जोड़ी का प्रतिनिधित्व करता है, जिस क्रम में वे मूल क्वेरी स्ट्रिंग में दिखाई देते हैं।

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)

वैकल्पिक रूप से, आप चीजों को आसान बनाने के लिए URL पर एक्सटेंशन जोड़ सकते हैं।

extension URL {
    var queryParameters: QueryParameters { return QueryParameters(url: self) }
}

class QueryParameters {
    let queryItems: [URLQueryItem]
    init(url: URL?) {
        queryItems = URLComponents(string: url?.absoluteString ?? "")?.queryItems ?? []
        print(queryItems)
    }
    subscript(name: String) -> String? {
        return queryItems.first(where: { $0.name == name })?.value
    }
}

आप इसके नाम से पैरामीटर तक पहुँच सकते हैं।

let url = URL(string: "http://example.com?param1=value1&param2=param2")!
print(url.queryParameters["param1"])

47

मैं थोड़ा लेट हो गया हूं, लेकिन अब तक दिए गए उत्तर मेरे काम नहीं आए जैसे मुझे चाहिए थे। आप इस कोड स्निपेट का उपयोग कर सकते हैं:

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म्यूट किए गए शब्दकोश में बच गए हैं ।

संपादित करें : स्विफ्ट संस्करण:

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

2
यह अच्छा जवाब है, लेकिन सबसे अच्छा नहीं है। आपको सावधान रहना चाहिए जब पैरामीटर बेस 64 एनकोडेड स्ट्रिंग्स जैसे कुछ हैं। जैसा कि @donleyp ने कहा, '=' वर्ण सामान्य मान हो सकता है। उदाहरण के लिए, base64 एन्कोडेड स्ट्रिंग को '=' वर्ण का उपयोग करके पैडिंग की आवश्यकता है।
khcpietro

@Aigori सही है अगर मैं गलत हूँ, लेकिन यह मुझे लगता है कि इस जवाब का समर्थन करता है base64। =पैडिंग के लिए उपयोग =अंत में डिकोड होने तक दिखाई नहीं देगा । यह, हालांकि, बिना मूल्य के क्वेरी परम का समर्थन नहीं करता है।
बोरिस

@ बोरिस उदाहरण के लिए, इस URL http://example.org/?base64=ZGF0YT1bMTUyLCAyNDI2LCAyMzE1XQ==को उत्तर कोड के साथ डिकोड करें । यह ZGF0YT1bMTUyLCAyNDI2LCAyMzE1XQनहीं लौटेगा ZGF0YT1bMTUyLCAyNDI2LCAyMzE1XQ==। बेशक, कुछ बेस 64 डिकोडर सही ढंग से डिकोड करते हैं, लेकिन, उदाहरण के लिए, NSData initWithBase64EncodedString:options:बिना पैडिंग के खाली स्ट्रिंग लौटाते हैं =। इसलिए, जब आप बेस 64 स्ट्रिंग को उत्तर कोड के साथ संभालते हैं तो आपको सावधान रहना चाहिए।
khcpietro

@Aigori हाँ आप सही कह रहे हैं, लेकिन इस मामले में url नहीं होगा http://example.org/?base64=ZGF0YT1bMTUyLCAyNDI2LCAyMzE1XQ==, यह http://example.org/?base64=ZGF0YT1bMTUyLCAyNDI2LCAyMzE1XQ%3D%3Dवैसा ही होगा जैसा कि url को इनकोड किया जाना चाहिए
Boris

10

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

यदि आप एक ही काम तेजी से करना चाहते हैं, तो आप एक एक्सटेंशन का उपयोग कर सकते हैं।

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

यदि आप NSURLComponentsनिम्नलिखित संक्षिप्त विस्तार का उपयोग कर रहे हैं तो यह भी चाल चलेगा:

extension NSURLComponents {

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

}

1
और स्विफ्ट 2 में, func getQueryStringParameter(name: String) -> String? { return self.queryItems?.filter({ (item) in item.name == name }).first?.value }
जेडीजा

4

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

4

स्विफ्ट 5

extension URL {
    func queryParams() -> [String:String] {
        let queryItems = URLComponents(url: self, resolvingAgainstBaseURL: false)?.queryItems
        let queryTuples: [(String, String)] = queryItems?.compactMap{
            guard let value = $0.value else { return nil }
            return ($0.name, value)
        } ?? []
        return Dictionary(uniqueKeysWithValues: queryTuples)
    }
}

3

यह कोड तीन मामलों में काम करता है

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

1
मैं विशेष रूप से YouTube आईडी निकालने के लिए एक समाधान की तलाश कर रहा था और मैं इस तथ्य को ध्यान में रखना भूल गया कि वैध यूट्यूब यूआरएल के कई रूप हैं। +1 धन्यवाद!
सोरस

3
-(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 में करें और आपको क्वैरिस्ट्रिंग के सभी तत्व मिल जाएंगे।


3

URL पर एक स्विफ्ट 3 एक्सटेंशन के रूप में इसका देर से समाधान

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
  }

}

सार


2

पूर्ण समारोह के रूप में:

+ (NSString *)getQueryComponentWithName:(NSString *)name  fromURL:(NSURL *)url{

NSString *component = nil;
if (url) {
    NSString *query = url.query;

    NSMutableDictionary *queryStringDictionary = [NSMutableDictionary dictionary];
    NSArray *urlComponents = [query 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];
    }

    component = [queryStringDictionary objectForKey:name];
}

return component;
}
[self getQueryComponentWithName:@"example" fromURL:[NSURL URLWithString:@"https://google.es/?example=test"]];

आप उदाहरण पर एक छोटी सी टाइपो है - कोष्ठक worngly रखा जाता है
Vaiden

2

एक पैरामीटर के रूप में क्वेरी पैरामीटर प्राप्त करने के लिए:

extension URL {
    var parameters: [String: String] {
        var parameters = [String: String]()
        if let urlComponents = URLComponents(url: self, resolvingAgainstBaseURL: false),
            let queryItems = urlComponents.queryItems {
            for queryItem in queryItems where queryItem.value != nil {
                parameters[queryItem.name] = queryItem.value
            }
        }
        return parameters
    }
}

या यदि आपके मामले में यह अधिक सुविधाजनक है तो वैकल्पिक लौटें।


0

NSURL में क्वेरी गुण क्वेरी स्ट्रिंग देगा। तब आप घटकों का उपयोग करके क्वेरी स्ट्रिंग को पार्स कर सकते हैं

    NSArray *parameters = [[url query] componentsSeparatedByString:@"&"];

    NSMutableDictionary *keyValuePairs = [NSMutableDictionary dictionary];

    for (NSString *eachParam in parameters)
    {
        NSArray *QryParts = [eachParam componentsSeparatedByString:@"="];
        if ( [QryParts count] == 2 )
        {
            keyValuePairs[QryParts[0]] = QryParts[1];
        }
        else
        {
            keyValuePairs[QryParts[0]] = QryParts[0];
        }
    }

NSString * name = [keyValuePairs valueForKey:@"name"];
NSString * username = [keyValuePairs valueForKey:@"username"];

0
- (NSString *)getLoginTokenFromUrl:(NSString *)urlString {
    NSURL *url = [NSURL URLWithString:urlString];
    NSArray *queryStrings = [url.query componentsSeparatedByString:@"&"];

    NSMutableDictionary *queryParams = [[NSMutableDictionary alloc] init];
    for (NSString *qs in queryStrings) {
        // Get the parameter name
        NSArray *components = [qs componentsSeparatedByString:@"="];
        NSString *key = [components objectAtIndex:0];

        // Get the parameter value
        NSString *value;
        if (components.count > 1) {
            value = [components objectAtIndex:1];
        }
        else {
            value = @"";
        }
        value = [value stringByReplacingOccurrencesOfString:@"+" withString:@" "];
        value = [value stringByReplacingPercentEscapesUsingEncoding:NSUTF8StringEncoding];

        queryParams[key] = value;
    }

    return [queryParams objectForKey:@"login_token"];
}

0

एक स्विफ्ट 2 दृष्टिकोण:

extension NSURL {

  var queryDictionary: [String: String] {
    var queryDictionary = [String: String]()
    guard let components = NSURLComponents(URL: self, resolvingAgainstBaseURL: false), queryItems = components.queryItems else { return queryDictionary }
    queryItems.forEach { queryDictionary[$0.name] = $0.value }
    return queryDictionary
  }

}

Gist डाउनलोड करें

हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.