【问题标题】:Parse NSURL path and query on iOS在 iOS 上解析 NSURL 路径和查询
【发布时间】:2010-12-30 08:35:43
【问题描述】:

是否有任何标准对象或函数来解析 NSURL 的组件?显然我可以写一个,但为什么要重新发明轮子呢?

[NSURL path] 将返回一个 NSString 就像 "argX=x&argY=y&argZ=z" 我宁愿找回的是一本包含{@"argX" => @"x", @"argY" => @"y", @"argZ" = @"z"}的字典

对于返回像“/partA/partB/partC”这样的字符串的路径,我宁愿得到一个结构为{[0] => @"partA", [1] => @"partB", [2] => @"partC"}的数组

我知道这是一个非常具体的问题,但它似乎是很多人想要的。

这是适用于 iOS 的!显然 NSURL 在 macOS 上有不同的功能。

【问题讨论】:

  • 好问题。你的意思是:如果 URL 是“/partA/partB/partC”,你想要“0 => partA, 1=> partB, 2=>partC”。如果 URL 是“/foo?partA=A&partB=B”,您需要“partA => A, partB => B”。如果 URL 是“/partA/partB/partC?foo=bar&ooga=booga”怎么办?在一个示例中,识别相关实体所需的重要信息在查询字符串中传递......在另一个示例中,标识信息在路径本身中以 rest 样式传递。
  • 我的意思是我想分别解析路径和查询。它不应该是结合这两个任务的一个功能。请参阅我在下面发布的代码以进行说明。如果有人回答现有的实现,我仍然很乐意接受。
  • 要记住的一点是,这是一个完全有效的查询字符串:“x=1&x=0&x=foo”,因此 NSDictionary 可能不是最好的表示(除非您使用数组作为值)。
  • @n8gray - 你说得对,我在下面的回答不涉及重复值。不过,我会避免在任何现实世界场景中出现像瘟疫这样的重复值,因为许多服务器(例如 PHP 服务器)最终将只有一个 x...x=>"foo" 的值,就像我的脚本一样。然而,PHP 用“x[]=1&x[]=foo”构建一个数组,而我的回答不会这样做。如果左侧参数名称以“[]”结尾,那么扩展我的示例以构建数组应该是一个简单的练习,所以我将把它留给需要它的任何人添加。谢谢!

标签: ios objective-c cocoa-touch nsurl


【解决方案1】:

如果您决定编写一个(我不确定是否有现有的方法可以获取您想要的组件),您可能需要使用 NSString 的 componentsSeparatedByString

【讨论】:

    【解决方案2】:

    您可能想查看pathComponents,它返回 URL 组件的数组。获取更多信息here

    【讨论】:

    • 我不相信这在 iphone 版本的 SDK 上可用。我应该澄清一下我正在开发 iphone OS。
    • [NSString pathComponents] 在 Cocoa 和 Cocoa Touch API 中都可用。在 iPhone 上,你可以用 [[NSURL path] pathComponents] 来模仿 OS X 10.6 的 [NSURL pathComponents]。
    • 啊完美,这就是我一直在寻找的,至少对于路径部分!
    • [NSString pathComponents] 状态的 Apple 文档:“请注意,此方法仅适用于文件路径(例如,URL 的字符串表示形式)。”
    • @MikeAbdullah:啊,好的。对于在这个 3 年前的问题上绊倒的其他人:从 iOS4 开始,您不再需要将 URL 转换为字符串,可以直接使用:-[NSURL pathComponents]。
    【解决方案3】:

    好吧,我烦了,写了一个通过类别扩展 NSString 的解决方案。我还没有测试过,但如果你想使用它,那就去吧。

    @interface NSString (ParseCategory)
    - (NSMutableDictionary *)explodeToDictionaryInnerGlue:(NSString *)innerGlue outterGlue:(NSString *)outterGlue;
    @end
    
    @implementation NSString (ParseCategory)
    
    - (NSMutableDictionary *)explodeToDictionaryInnerGlue:(NSString *)innerGlue outterGlue:(NSString *)outterGlue {
        // Explode based on outter glue
        NSArray *firstExplode = [self componentsSeparatedByString:outterGlue];
        NSArray *secondExplode;
    
        // Explode based on inner glue
        NSInteger count = [firstExplode count];
        NSMutableDictionary *returnDictionary = [NSMutableDictionary dictionaryWithCapacity:count];
        for (NSInteger i = 0; i < count; i++) {
            secondExplode = [(NSString *)[firstExplode objectAtIndex:i] componentsSeparatedByString:innerGlue];
            if ([secondExplode count] == 2) {
                [returnDictionary setObject:[secondExplode objectAtIndex:1] forKey:[secondExplode objectAtIndex:0]];
            }
        }
    
        return returnDictionary;
    }
    
    @end
    

    它是这样称呼的:

    NSMutableDictionary *parsedQuery = [[myNSURL query] explodeToDictionaryInnerGlue:@"=" outterGlue=@"&"]
    

    为了解析 NSURL 的路径部分(即@"/partA/partB/partC"),只需调用这个:

    NSArray *parsedPath = [[nyNSURL path] componentsSeperatedByString:@"/"];
    

    请注意,parsedPath[0] 将是一个空字符串,因为前导 /!

    编辑 - 这是一个 NSURL 的类别扩展,供您使用。它去除了最初的“/”,所以你没有空的 0 索引。

    @implementation NSURL (ParseCategory)
    
    - (NSArray *)pathArray {
        // Create a character set for the slash character
        NSRange slashRange;
        slashRange.location = (unsigned int)'/';
        slashRange.length = 1;
        NSCharacterSet *slashSet = [NSCharacterSet characterSetWithRange:slashRange];
    
        // Get path with leading (and trailing) slashes removed
        NSString *path = [[self path] stringByTrimmingCharactersInSet:slashSet];
    
        return [path componentsSeparatedByCharactersInSet:slashSet];
    }
    
    - (NSDictionary *)queryDictionary {
        NSDictionary *returnDictionary = [[[[self query] explodeToDictionaryInnerGlue:@"=" outterGlue:@"&"] copy] autorelease];
        return returnDictionary;
    }
    
    @end
    

    【讨论】:

    • 不知道为什么有人不赞成这个...我猜这会教我分享代码?如果您发表评论,我真的不介意,但我只是假设您是一个随机的巨魔。嗨巨魔。
    • 谢谢,这对我来说很好用。请注意,您可能还需要对各个查询字符串值进行 URL 解码。我为此使用以下代码,首先处理百分比转义,然后用空格替换“+”,不幸的是第一个没有这样做:[[value stringByReplacingPercentEscapesUsingEncoding:NSUTF8StringEncoding] stringByReplacingOccurrencesOfString:@"+" withString:@" "]
    • 非常欢迎。是的,我把编码/解码的问题排除在这些函数之外。
    【解决方案4】:

    Sam Soffes 为 NSURL / NSDictionary 创建了一个维护良好的类别。可以在这里找到:https://github.com/samsoffes/sstoolkit/

    【讨论】:

      【解决方案5】:

      这是我用来解析查询字符串的内容

      // Parse the individual parameters
      // parameters = @"hello=world&foo=bar";
      NSMutableDictionary *dictParameters = [[NSMutableDictionary alloc] init];
      NSArray *arrParameters = [parameters componentsSeparatedByString:@"&"];
      for (int i = 0; i < [arrParameters count]; i++) {
          NSArray *arrKeyValue = [[arrParameters objectAtIndex:i] componentsSeparatedByString:@"="];
          if ([arrKeyValue count] >= 2) {
              NSMutableString *strKey = [NSMutableString stringWithCapacity:0];
              [strKey setString:[[[arrKeyValue objectAtIndex:0] lowercaseString] stringByReplacingPercentEscapesUsingEncoding: NSUTF8StringEncoding]];
              NSMutableString *strValue   = [NSMutableString stringWithCapacity:0];
              [strValue setString:[[[arrKeyValue objectAtIndex:1]  stringByReplacingOccurrencesOfString:@"+" withString:@" "] stringByReplacingPercentEscapesUsingEncoding: NSUTF8StringEncoding]];
              if (strKey.length > 0) [dictParameters setObject:strValue forKey:strKey];
          }
      }
      NSLog(@"Parameters: %@", dictParameters);
      

      【讨论】:

        【解决方案6】:

        在 iOS 8 和 OS X 10.10 中引入的是NSURLQueryItem,可用于构建查询。来自NSURLQueryItem 上的文档:

        NSURLQueryItem 对象表示 URL 查询部分中项目的单个名称/值对。您可以将查询项与 NSURLComponents 对象的 queryItems 属性一起使用。

        您可以通过首先创建NSURLComponents,从 URL 中检索查询项:

        NSURL *url = [NSURL URLWithString:@"http://stackoverflow.com?q=ios&count=10"];
        NSURLComponents *components = [NSURLComponents componentsWithURL:url 
                                                       resolvingAgainstBaseURL:YES];
        for (NSURLQueryItem *item in components.queryItems) {
            NSLog(@"name: %@, value: %@", item.name, item.value);
        }
        // name: q, value: ios
        // name: count, value: 10
        

        请注意,-queryItems 的返回值是一个数组,而不是字典。这是因为以下是有效的 URL。注意两个相同的“键”foo

        http://google.com?foo=bar&amp;foo=baz

        要通过查询项创建 URL,请使用指定的初始化程序 queryItemWithName:value:,然后将它们添加到 NSURLComponents 以生成 NSURL。例如:

        NSString *urlString = @"http://stackoverflow.com";
        NSURLComponents *components = [NSURLComponents componentsWithString:urlString];
        NSURLQueryItem *search = [NSURLQueryItem queryItemWithName:@"q" value:@"ios"];
        NSURLQueryItem *count = [NSURLQueryItem queryItemWithName:@"count" value:@"10"];
        components.queryItems = @[ search, count ];
        NSURL *url = components.URL; // http://stackoverflow.com?q=ios&count=10
        

        请注意,问号和 & 号是自动处理的。从参数字典创建NSURL 非常简单:

        NSDictionary *queryDictionary = @{ @"q": @"ios", @"count": @"10" };
        NSMutableArray *queryItems = [NSMutableArray array];
        for (NSString *key in queryDictionary) {
            NSURLQueryItem *item = [NSURLQueryItem queryItemWithName:key 
                                                               value:queryDictionary[key]]; 
            [queryItems addObject:item];
        }
        components.queryItems = queryItems;
        

        我还写了一篇博文,其中包含更多详细信息,Building NSURLs with NSURLQueryItems

        【讨论】:

        • 酷!只是给开发人员的一个提示——如果你使用重复的 GET 参数,你就会陷入痛苦的世界。没有定义如何处理这些的规范,并且不同的语言/平台构成了自己的规则。见stackoverflow.com/questions/1746507/…
        猜你喜欢
        • 2011-04-29
        • 1970-01-01
        • 2014-10-22
        • 2019-01-13
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2021-09-20
        • 1970-01-01
        相关资源
        最近更新 更多