【问题标题】:Percent escaping query url strings转义查询 url 字符串的百分比
【发布时间】:2014-01-08 16:44:02
【问题描述】:

我得到了http://maps.apple.com/maps?saddr=41.447910,-74.357881&daddr=719 Old Route 9 North, Wappingers Falls, NY 12590的NSString

但是我需要将上面的字符串转换成这个字符串,以便在地图中显示位置

http://maps.apple.com/maps?saddr=41.447910,-74.357881&daddr=719+Old%20Route+9+North%2CWappingers+Falls%2CNY+12590

请告诉我。

【问题讨论】:

  • 您是否尝试过查找 percentEscaping 的 NSStrings。很确定它不会为您添加+ 符号,但仔细研究它不会有什么坏处。

标签: ios sdk nsstring


【解决方案1】:

您可以通过以下方式做到这一点...

NSString *theOrigString = @"http://maps.apple.com/maps?saddr=41.447910,-74.357881&daddr=719 Old Route 9 North, Wappingers Falls, NY 12590";

NSString *formattedString = [theOrigString stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding];

NSLog(@"%@", formattedString);

输出

http://maps.apple.com/maps?saddr=41.447910,-74.357881&daddr=719%20Old%20Route%2‌​09%20North,%20Wappingers%20Falls,%20NY%2012590

这将用 %20 等替换空格。

然后您可以将其用作 url 字符串。

【讨论】:

  • 不。您不能以这种方式对整个 URL 进行编码。看我的回答。
  • @DuncanC 是的,你错了。对不起。我刚刚尝试了我的两行并 NSLogged 结果...http://maps.apple.com/maps?saddr=41.447910,-74.357881&daddr=719%20Old%20Route%209%20North,%20Wappingers%20Falls,%20NY%2012590
  • stringByAddingPercentEscapesUsingEncoding: 方法有时适用于某些目的,但它通常不是您想要的,因为它会尝试对整个 URL 进行编码,这意味着它不会对任何 URL 保留字符进行编码.因此,在这种奇怪的情况下,该方法实际上是正确的,但这只是因为输入非常不寻常(一个完整的 URL,其中去除了百分比编码,其中原始百分比编码的字符都不在 URL 保留字符列表中)。当然,更安全的答案是“不要在...的途中对字符串进行 URL 解码”。
【解决方案2】:

一个老问题,但这是你需要的:

-(NSString*) encodeToPercentEscapeString:(NSString *)string {
return (NSString *)CFBridgingRelease(CFURLCreateStringByAddingPercentEscapes(NULL,
                                        (CFStringRef) string,
                                        NULL,
                                        (CFStringRef) @"!*'();:@&=+$,/?%#[]",
                                        kCFStringEncodingUTF8)); }

-(NSString*) decodeFromPercentEscapeString:(NSString *)string {
return (NSString *)CFBridgingRelease(CFURLCreateStringByReplacingPercentEscapesUsingEncoding(NULL,
                                                        (CFStringRef) string,
                                                        CFSTR(""),
                                                        kCFStringEncodingUTF8)); }

【讨论】:

    【解决方案3】:

    看看NSStringstringByAddingPercentEscapesUsingEncoding:

    NSString *urlString = @"http://maps.apple.com/maps?saddr=41.447910,-74.357881&daddr=719 Old Route 9 North, Wappingers Falls, NY 12590";
    
    NSString *encodedString = [urlString stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding]
    

    【讨论】:

    • 你不能这样编码。您必须单独编码参数。
    • DuncanC 和@Sulthan 在这里都错了。这和 Chris 写的完全一样。
    • 嗯似乎总是对我有用,我想将 baseUrl 分开然后附加编码的查询字符串可能是理想的。
    • @ChrisWagner 同样,对我也有用。那好吧。我喜欢对整个 URL 进行编码,因为它可以更轻松地调试分隔部分。我正在编码一个完全人类可读的 URL,而不是从难以阅读的单独位创建 URL。
    • @Fogmeister,仅当您可以确定 URL 的字符串部分不包含用作 URL 中的分隔符的字符时,才能对整个 URL 进行编码。
    【解决方案4】:

    百分比编码背后的原因只是来自RFC 3986。简而言之,您应该百分比转义 URI 查询参数 的值以转义 保留字符 ("!*'();:@&=+$,/? %#[]")。这样做可以正确解码编码的 URI - 为了简单起见,假设双方的编码相同。

    正如 Duncan 和 Fogmeister 所指出的,Apple 的 stringByAddingPercentEscapesUsingEncoding 非常友好,但总的来说,它是错误的 - 或者至少不符合 RFC 3986 - 因为不转义字符,如“/:&%?”。

    一个更通用和更强大的解决方案是这样的

    NSString * HKObjectToString(id object) {
        return [NSString stringWithFormat:@"%@", object];
    }   
    
    NSString * HKPercentEscapedString(id object, CFStringEncoding encoding) {
        NSString *string = HKObjectToString(object);
        return ((NSString *)CFBridgingRelease(CFURLCreateStringByAddingPercentEscapes(NULL, (__bridge CFStringRef) string, NULL,
                                                                                  CFSTR("!*'();:@&=+$,/?%#[]"),
                                                                                  encoding)));
    }
    
    ...
    @implementation NSDictionary (URLAdditions)
    ...
    - (NSString *)percentEscapedQueryStringWithEncoding:(CFStringEncoding)encoding
    {
        NSMutableArray *queryParts = [[NSMutableArray alloc] init];
        for (NSString *key in [self allKeys]) {
            NSString *part = [NSString stringWithFormat:@"%@=%@", HKPercentEscapedString(key, encoding), HKPercentEscapedString(HKObjectToString(self[key]), encoding)];
            [queryParts addObject:part];
        }
        return [queryParts componentsJoinedByString:@"&"];
    }
    ...
    @end 
    
    ...
    @implementation NSString (StringHelper)
    ...
    + (NSString *)URIEncodedWithStringURI:(NSString *)baseURI queryParameters:(NSDictionary *)queryParams URIEncoding:(CFStringEncoding)encoding
    {
        return [NSString stringWithFormat:@"%@?%@", baseURI, [queryParams percentEscapedQueryStringWithEncoding:encoding]];
    }
    ...
    @end
    

    有关更多详细信息,请尝试查看 github 上的这个公共 repo

    【讨论】:

      【解决方案5】:

      这个问题是有问题的,因为输入的数据被损坏了。在代码中的某个较早时间点,此 URL 被解码为单个字符串。您永远不应该这样做,因为它可能导致 URL 不同部分之间的区别丢失并且永远无法恢复的情况。例如,假设我有这个 URL:

      http://www.example.com/folder/this%2Fthat.html

      解码后变成

      http://www.example.com/folder/this/that.html

      并且没有办法将其恢复为原始内容,因为无法知道哪些斜线是真实的,哪些应该编码为 %2F。区别就消失了。

      因此,当您使用 URL 时,务必尽可能将它们保留为原始形式,并且当您必须对 URL 进行解码时,请分段进行 - 即首先将所有路径组件,查询字符串等,然后将查询字符串中的字段分开(如果适用),最后单独解码每个部分。

      之后,您需要使用 CFURLCreateStringByReplacingPercentEscapesUsingEncoding 对每个部分进行重新编码,因为上面的 NSString 方法不会对斜杠、& 和其他特殊 URL 字符进行百分比编码。

      但在您的情况下,最好的办法是找到解码 URL 的代码,并将其撕掉,以便您拥有原始的、未损坏的 URL。如果并且如果不可能,则 stringByAddingPercentEscapesUsingEncoding: 方法可以对要编码的内容做出“最佳猜测”,只要您了解对于任意 URL,该解决方案不一定有效。

      【讨论】:

        【解决方案6】:

        已编辑:

        Sulthan 说得有道理。如果字符串部分(如本例中的地址)可能包含保留的 URL 字符(“/”、“:”、“&”、“%”、“?”等),则不能对整个 URL 进行百分比编码。

        stringByAddingPercentEscapesUsingEncoding 方法编码空格,但不编码斜杠、冒号等。因此,如果地址字符串包含其中任何一个,则 URL 的接收者无法分辨 URL 的语法部分和数据是什么。

        我有一个 NSString 类别也可以转义这些字符:

        标题

        #import <Foundation/Foundation.h>
        
        @interface NSString (URLEncoding) 
        - (NSString *)stringByAddingPercentEscapes;
        - (NSString *)stringByReplacingPercentEscapes; 
        @end 
        NSString *mapURLStringTemplate = 
          @"http://maps.apple.com/maps?saddr=%f,%f&daddr=%@";
        

        身体:

        #import "StringCategory.h"
        
        CFStringRef charsToEscape = CFSTR(":/&=");
        
        @implementation NSString (URLEncoding) 
        
        - (NSString *)stringByAddingPercentEscapes 
        { 
            return (NSString *)CFBridgingRelease(CFURLCreateStringByAddingPercentEscapes(NULL, 
                                                                        (CFStringRef)self, NULL, charsToEscape, 
                                                                        CFStringConvertNSStringEncodingToEncoding(NSUTF8StringEncoding))); 
        } 
        
        - (NSString *)stringByReplacingPercentEscapes 
        { 
            return (NSString *)CFBridgingRelease(CFURLCreateStringByReplacingPercentEscapes(kCFAllocatorDefault,(CFStringRef)self, CFSTR(""))); 
        } 
        
        @end 
        

        并使用它:

        NSString *escapedAddressString = 
          [addressString stringByAddingPercentEscapes];
        
        NSString *mapURLString = 
          [NSString stringWithFormat: mapURLStringTemplate, 
          latitude, 
          longitude, 
          escapedAddressString];
        

        【讨论】:

        • 不,您可以对整个 URL 进行编码。你不必花时间把它拆开。也许是因为您使用的是 ASCII 编码而不是 UTF8?
        • 实际上,它也适用于 ASCII 编码。你是否真的检查过它不起作用。我想你会感到惊讶。
        • @Fogmeister:你是对的。我有一个自定义的 NSString 类别,它可以从用户输入的字符串中转义所有不同的字符,这些字符会弄乱 URL 解析(“/”、“:”、“&”、“%”、“?”等)我使用那。我想我忘记了 stringByAddingPercentEscapesUsingEncoding 没有转义这些字符。但是,它没有逃脱这些字符的事实是另一个问题来源。例如,如果地址字符串中有斜线,则可能会弄乱 URL 解析。当然,斜线在地址中并不常见,但完全格式化您的数据是值得的。
        猜你喜欢
        • 2011-07-01
        • 2023-03-23
        • 2017-04-30
        • 2011-07-02
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2011-10-21
        相关资源
        最近更新 更多