Objective-c iPhone 百分比编码字符串?

我想得到这些特定字母的百分比编码字符串,如何在目标-c 中做到这一点?

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

百分号编码维基

请使用这个字符串进行测试,看看它是否有效:

myURL = @"someurl/somecontent"

我希望字符串看起来像:

myEncodedURL = @"someurl%2Fsomecontent"

我已经尝试使用 stringByAddingPercentEscapesUsingEncoding: NSASCIIStringEncoding,但它不工作,结果仍然是原来的字符串相同。请指教。

50192 次浏览

NSString 的 编码:看起来就像你想要的。

编辑 : 这里有一个使用 CFURLCreateStringByAddingPercentEscapes的例子,originalString可以是 NSString也可以是 CFStringRef

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

请注意,这是未经测试的。您应该查看一下 文件页,以确保理解 CFStringRef的内存分配语义、免费桥接的思想,等等。

另外,我也不知道(我的第一反应)在 legalURLCharactersToBeEscaped参数中指定的哪些字符无论如何都会被转义(因为在 URL 中是非法的)。您可能需要检查这一点,不过为了安全起见,最好直接指定要转义的字符。

我把这个答案做成一个社区维基,这样对 CoreFoundation 有更多了解的人可以做出改进。

NSString *encodedString = [myString stringByAddingPercentEscapesUsingEncoding:NSASCIIStringEncoding];

它不会内联替换字符串; 它将返回一个新字符串。方法以“ string”开头这一事实暗示了这一点。这是一种基于当前 NSString 实例化 NSString 新实例的方便方法。

注意——这个新字符串将被 autorelease化,所以在使用完它之后不要调用 release。

我发现 stringByAddingPercentEscapesUsingEncoding:CFURLCreateStringByAddingPercentEscapes()都不足。NSString方法遗漏了相当多的字符,CF 函数只允许您说出要转义的(特定)字符。正确的规范是转义除小集合外的所有字符。

为了解决这个问题,我创建了一个 NSString分类方法来正确地编码字符串。它将百分比编码一切除了 [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;
}

如果您正在 Objective-c 程序中使用 ASI HttpRequest 库,这是我极力推荐的,那么您可以在其 ASIFormDataRequest 对象上使用“ encodeURL”助手 API。不幸的是,这个 API 不是静态的,所以也许值得在项目中使用它的实现创建一个扩展。

直接从 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的一个包装器,负责应该正确转义的所有字符。

IOS7SDK 现在有了一个比 stringByAddingPercentEscapesUsingEncoding更好的选择,它允许您指定除了某些允许的字符之外的所有字符都要转义。如果你正在部分地构建网址,那么它会很好地工作:

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 的其他部分很少是变量,但是在 NSULUtitility 类别中也有一些常量:

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

[NSCharacterSet URLQueryAllowedCharacterSet]包括 URL 的查询部分(以 ?开始,在 #之前,如果有片段的话)所允许的字符的 所有,包括 ?&=字符,这些字符用于分隔参数名称和值。对于具有字母数字值的查询参数,这些字符中的任何一个都可能包含在用于生成查询字符串的变量的值中。在这种情况下,查询字符串的每个 一部分都需要转义,这只需要多做一点工作:

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,比如用于回调或重定向:

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

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

在我注意到罗布的回答之前,我继续把戴夫的回答移植到斯威夫特上。我把它放在这里,以防有人感兴趣:

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

遵循 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

在 Swift4中:

 var str = "someurl/somecontent"


let percentEncodedString = str.addingPercentEncoding(withAllowedCharacters: .alphanumerics)