提问人:Stephen Darlington 提问时间:9/5/2008 最后编辑:LebyrtStephen Darlington 更新时间:6/7/2019 访问量:1569
在 Cocoa 应用中打开非标准网址
Opening a non-standard URL in a Cocoa app
问:
在我正在编写的应用程序中,我有一些这样的代码:
NSWorkspace* ws = [NSWorkspace sharedWorkspace];
NSString* myurl = @"http://www.somewebsite.com/method?a=%d";
NSURL* url = [NSURL URLWithString:myurl];
[ws openURL:url];
主要区别在于 myurl 来自我无法控制的地方。请注意 URL 中的 %d,这并不完全正确,意味着 URLWithString 失败,返回 nil。
处理这个问题的“正确”方法是什么?我是否需要解析字符串并正确编码参数?或者可可中有什么聪明的方法可以为我完成所有艰苦的工作?
答:
我认为这里的行为是正确的,因为 %d 不是 URL 的有效组成部分(% 是转义符,但希望它后面有两个十六进制字符)。
你不能只对给定的 URL 进行 URL 编码,因为这也会对 /s 和 ?s 进行编码,这是你不想要的。
那么,问题是,这里的正确行为是什么?
也许你会希望它变成......
http://www.somewebsite.com/method?a=%25d
(即 % 被编码为 URL 中 % 的编码版本,因此当方法获取输入时,它会将 a 视为设置为 %d)
我不认为有任何库函数可以为您做这种事情,因为没有“正确”的方法可以做到这一点。关于他,您唯一可以做的正确事情是返回一条错误消息,指出您获得的 URL 无效(就像 URLWithString 一样)
如果您想尝试处理输入,我想您需要在 URL 中搜索任何没有紧随其后的两个十六进制字符的 % 符号,然后在这种情况下将 % 替换为 %25。使用正则表达式应该很有可能,尽管我怀疑如果您的 URL 开始包含 ASCII 字符集之外的字符的编码版本,可能会有一些额外的复杂性。
我不确定这是否正是您要找的,但是 NSString 中有一个方法可以清理 URL:
stringByAddingPercentEscapesUsingEncoding:
不幸的是,您需要比Apple提供的更聪明:
stringByAddingPercentEscapesUsingEncoding:
这将转义所有无效的 URL 字符,以便有效的“http://foo.com/hey%20dude/”变为“http://foo.com/hey%2520dud/”,这不是我们想要的。
我制作了一个 NSURL 类别,它做了正确的事情并处理奇怪的字符串,例如具有部分编码的字符串(即“http://foo.com/hey dude/i%20do%20it/”)。
代码如下:
@interface NSURL (SmartEncoding)
+ (NSURL *)smartURLWithString:(NSString *)str;
@end
@implementation NSURL (SmartEncoding)
+ (NSURL *)smartURLWithString:(NSString *)str
{
CFStringRef preprocessed = CFURLCreateStringByReplacingPercentEscapesUsingEncoding(NULL, (CFStringRef)str, CFSTR(""), kCFStringEncodingUTF8);
if (!preprocessed)
preprocessed = CFURLCreateStringByReplacingPercentEscapesUsingEncoding(NULL, (CFStringRef)str, CFSTR(""), kCFStringEncodingASCII);
if (!preprocessed)
return [NSURL URLWithString:str];
CFStringRef sanitized = CFURLCreateStringByAddingPercentEscapes(NULL, preprocessed, NULL, NULL, kCFStringEncodingUTF8);
CFRelease(preprocessed);
NSURL *result = (NSURL*)CFURLCreateWithString(NULL, sanitized, NULL);
CFRelease(sanitized);
return [result autorelease];
}
@end
它适用于 UTF8 字符串编码和 ASCII 字符串。
评论