Objective-C的iPhone百分比编码一个string?

我想获得这些特定字母的百分比编码string,如何在objective-c中做到这一点?

Reserved characters after percent-encoding ! * ' ( ) ; : @ & = + $ , / ? # [ ] %21 %2A %27 %28 %29 %3B %3A %40 %26 %3D %2B %24 %2C %2F %3F %23 %5B %5D 

编码百分比的wiki

请testing这个string,看看它是否工作:

 myURL = @"someurl/somecontent" 

我想这个string看起来像:

 myEncodedURL = @"someurl%2Fsomecontent" 

我尝试过使用stringByAddingPercentEscapesUsingEncoding: NSASCIIStringEncoding但它不起作用,结果仍然是原来的string。 请指教。

我发现stringByAddingPercentEscapesUsingEncoding:CFURLCreateStringByAddingPercentEscapes()是不够的。 NSString方法错过了很多字符,而CF函数只能让你说出你想要转义哪些(特定的)字符。 正确的规格是逃避除了一个小集合以外的所有字符。

为了解决这个问题,我创build了一个NSString类别方法来正确编码一个string。 除了[a-zA-Z0-9.-_~] ,它将编码所有内容的百分比,还将把空格编码为+ (根据此规范 )。 它也将正确处理编码unicode字符。

 - (NSString *) URLEncodedString_ch { NSMutableString * output = [NSMutableString string]; const unsigned char * source = (const unsigned char *)[self UTF8String]; int sourceLen = strlen((const char *)source); for (int i = 0; i < sourceLen; ++i) { const unsigned char thisChar = source[i]; if (thisChar == ' '){ [output appendString:@"+"]; } else if (thisChar == '.' || thisChar == '-' || thisChar == '_' || thisChar == '~' || (thisChar >= 'a' && thisChar <= 'z') || (thisChar >= 'A' && thisChar <= 'Z') || (thisChar >= '0' && thisChar <= '9')) { [output appendFormat:@"%c", thisChar]; } else { [output appendFormat:@"%%%02X", thisChar]; } } return output; } 

iOS 7 SDK现在有了一个比stringByAddingPercentEscapesUsingEncoding更好的替代方法,它可以让你指定除了某些允许的字符之外,所有的字符都被转义。 如果你正在build立部分的url,那么效果很好:

 NSString * unescapedQuery = [[NSString alloc] initWithFormat:@"?myparam=%d", numericParamValue]; NSString * escapedQuery = [unescapedQuery stringByAddingPercentEncodingWithAllowedCharacters:[NSCharacterSet URLQueryAllowedCharacterSet]]; NSString * urlString = [[NSString alloc] initWithFormat:@"http://ExampleOnly.com/path.ext%@", escapedQuery]; 

虽然URL的其他部分不太可能是variables,但在NSURLUtilities类别中也有一些常量:

 [NSCharacterSet URLHostAllowedCharacterSet] [NSCharacterSet URLUserAllowedCharacterSet] [NSCharacterSet URLPasswordAllowedCharacterSet] [NSCharacterSet URLPathAllowedCharacterSet] [NSCharacterSet URLFragmentAllowedCharacterSet] 

[NSCharacterSet URLQueryAllowedCharacterSet]包含URL查询部分允许的所有字符(以?开始的部分以及#之前的部分,如果有的话),包括? 以及用于分隔参数名称和值的&=字符。 对于包含字母数字值的查询参数,这些字符中的任何字符都可能包含在用于构build查询string的variables的值中。 在这种情况下,查询string的每个部分都需要被转义,这只需要更多的工作:

 NSMutableCharacterSet * URLQueryPartAllowedCharacterSet; // possibly defined in class extension ... // ... and built in init or on first use URLQueryPartAllowedCharacterSet = [[NSCharacterSet URLQueryAllowedCharacterSet] mutableCopy]; [URLQueryPartAllowedCharacterSet removeCharactersInString:@"&+=?"]; // %26, %3D, %3F // then escape variables in the URL, such as values in the query and any fragment: NSString * escapedValue = [anUnescapedValue stringByAddingPercentEncodingWithAllowedCharacters:URLQueryPartAllowedCharacterSet]; NSString * escapedFrag = [anUnescapedFrag stringByAddingPercentEncodingWithAllowedCharacters:[NSCharacterSet URLFragmentAllowedCharacterSet]]; NSString * urlString = [[NSString alloc] initWithFormat:@"http://ExampleOnly.com/path.ext?myparam=%@#%@", escapedValue, escapedFrag]; NSURL * url = [[NSURL alloc] initWithString:urlString]; 

unescapedValue甚至可以是整个URL,例如callback或redirect:

 NSString * escapedCallbackParamValue = [anAlreadyEscapedCallbackURL stringByAddingPercentEncodingWithAllowedCharacters:URLQueryPartAllowedCharacterSet]; NSURL * callbackURL = [[NSURL alloc] initWithString:[[NSString alloc] initWithFormat:@"http://ExampleOnly.com/path.ext?callback=%@", escapedCallbackParamValue]]; 

注意:不要使用NSURL initWithScheme:(NSString *)scheme host:(NSString *)host path:(NSString *)path具有查询string的URL NSURL initWithScheme:(NSString *)scheme host:(NSString *)host path:(NSString *)path ,因为它将向path添加更多百分比的转义。

 NSString *encodedString = [myString stringByAddingPercentEscapesUsingEncoding:NSASCIIStringEncoding]; 

它不会replace你的内联string; 它会返回一个新的string。 这意味着方法以“string”开始。 这是基于当前NSString实例化NSString的新实例的一种便捷方法。

注意 – 新的string会被autorelease ,所以当你完成它的时候不要调用release。

NSString的stringByAddingPercentEscapesUsingEncoding:看起来像你之后。

编辑 :这是一个使用CFURLCreateStringByAddingPercentEscapes的例子。 originalString可以是NSStringCFStringRef

 CFStringRef newString = CFURLCreateStringByAddingPercentEscapes(kCFAllocatorDefault, originalString, NULL, CFSTR("!*'();:@&=+@,/?#[]"), kCFStringEncodingUTF8); 

请注意,这是未经testing。 您应该查看文档页面 ,以确保您了解CFStringRef的内存分配语义,免费桥接的概念等等。

另外,我不知道(在我的头顶)在legalURLCharactersToBeEscaped参数中指定的字符中的legalURLCharactersToBeEscaped字符会被转义(由于在URL中是非法的)。 你可能想检查一下,虽然也许只是为了安全起见,直接指定你想要逃脱的字符。

我将这个答案作为一个社区维基,以便对CoreFoundation有更多了解的人可以改进。

如果您在您的objective-c程序中使用ASI HttpRequest库 ,那么我不能推荐它足够高,那么您可以在其ASIFormDataRequest对象上使用“encodeURL”助手API。 不幸的是,API不是静态的,所以也许值得在你的项目中使用它的实现来创build一个扩展。

直接从ASIFormDataRequest.m中为encodeURL实现复制的代码是:

 - (NSString*)encodeURL:(NSString *)string { NSString *newString = NSMakeCollectable([(NSString *)CFURLCreateStringByAddingPercentEscapes(kCFAllocatorDefault, (CFStringRef)string, NULL, CFSTR(":/?#[]@!$ &'()*+,;=\"<>%{}|\\^~`"), CFStringConvertNSStringEncodingToEncoding([self stringEncoding])) autorelease]); if (newString) { return newString; } return @""; } 

正如你所看到的,它基本上是CFURLCreateStringByAddingPercentEscapes一个包装,它负责处理所有应该正确转义的字符。

遵循RFC3986标准,以下是我用于编码URL组件的内容:

 // https://tools.ietf.org/html/rfc3986#section-2.2 let rfc3986Reserved = NSCharacterSet(charactersInString: "!*'();:@&=+$,/?#[]") let encoded = "email+with+plus@example.com".stringByAddingPercentEncodingWithAllowedCharacters(rfc3986Reserved.invertedSet) 

输出: email%2Bwith%2Bplus%40example.com

在我注意到Rob的回答之前,似乎工作得很好,并且因为它更干净,所以我select了Dave的答案Swift。 我会把它留在这里,以防有人感兴趣:

 public extension String { // For performance, I've replaced the char constants with integers, as char constants don't work in Swift. var URLEncodedValue: String { let output = NSMutableString() guard let source = self.cStringUsingEncoding(NSUTF8StringEncoding) else { return self } let sourceLen = source.count var i = 0 while i < sourceLen - 1 { let thisChar = source[i] if thisChar == 32 { output.appendString("+") } else if thisChar == 46 || thisChar == 45 || thisChar == 95 || thisChar == 126 || (thisChar >= 97 && thisChar <= 122) || (thisChar >= 65 && thisChar <= 90) || (thisChar >= 48 && thisChar <= 57) { output.appendFormat("%c", thisChar) } else { output.appendFormat("%%%02X", thisChar) } i++ } return output as String } } 

在Swift4中:

  var str = "someurl/somecontent" let percentEncodedString = str.addingPercentEncoding(withAllowedCharacters: .alphanumerics)