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

Hoa*_*ham 70 iphone objective-c

我想获取这些特定字母的百分比编码字符串,如何在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
Run Code Online (Sandbox Code Playgroud)

百分比编码维基

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

myURL = @"someurl/somecontent"
Run Code Online (Sandbox Code Playgroud)

我希望字符串看起来像:

myEncodedURL = @"someurl%2Fsomecontent"
Run Code Online (Sandbox Code Playgroud)

我试过stringByAddingPercentEscapesUsingEncoding: NSASCIIStringEncoding已经但它不起作用,结果仍然与原始字符串相同.请指教.

Dav*_*ong 142

我发现,无论stringByAddingPercentEscapesUsingEncoding:CFURLCreateStringByAddingPercentEscapes()不足.该NSString方法错过了很多字符,CF函数只允许您说出要转义的特定字符.正确的规范是逃避除小集之外的所有字符.

为了解决这个问题,我创建了一个NSString类别方法来正确编码字符串.它将百分比编码所有EXCEPT [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;
}
Run Code Online (Sandbox Code Playgroud)

  • 请注意,将空格编码为+而不是%20是根据x-www-form-urlencoded,而不是oauth-1,3.6(您发布的规范链接). (6认同)
  • @mihir当然.这只是一种转换方法.如果您不想编码整个字符串,请不要传入整个字符串... (6认同)
  • 雅有你的观点,实际上我实现了一切,而不是意识到这个问题,现在需要单独编码每个参数......非常麻烦...... :( (3认同)

Rob*_*com 103

iOS 7 SDK现在有一个更好的替代方案stringByAddingPercentEscapesUsingEncoding,让您指定除了某些允许的字符外,您希望所有字符都被转义.如果您在部分中构建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];
Run Code Online (Sandbox Code Playgroud)

虽然URL的其他部分通常不是变量,但NSURLUtilities类别中也有常量:

[NSCharacterSet URLHostAllowedCharacterSet]
[NSCharacterSet URLUserAllowedCharacterSet]
[NSCharacterSet URLPasswordAllowedCharacterSet]
[NSCharacterSet URLPathAllowedCharacterSet]
[NSCharacterSet URLFragmentAllowedCharacterSet]
Run Code Online (Sandbox Code Playgroud)

[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];
Run Code Online (Sandbox Code Playgroud)

unescapedValue甚至可以是一个完整的URL,如回调或重定向:

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

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

  • 有一个不那么罗嗦的替代方案:`URLQueryPartAllowedCharacterSet = [[NSCharacterSet URLQueryAllowedCharacterSet] mutableCopy]; [URLQueryPartAllowedCharacterSet removeCharactersInString:@"?&= @ + /'"];`我还在Mac上测试了100,000次迭代,发现这个次数比调用`removeCharactersInRange:`多次快一点. (9认同)
  • 只是缺少“+”,因此您可能需要添加“[URLQueryPartAllowedCharacterSet removeCharactersInRange:NSMakeRange('+', 1)];”,但除此之外,此代码非常适合转义字符串,谢谢! (2认同)

Dav*_*vid 5

NSString的stringByAddingPercentEscapesUsingEncoding:看起来像你所追求的.

编辑:这是一个使用CFURLCreateStringByAddingPercentEscapes相反的例子.originalString可以是一个NSString或一个CFStringRef.

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

请注意,这是未经测试的.你应该看看文档页面,以确保您了解内存分配语义CFStringRef,免费桥接的思想,等等.

另外,我不知道(我的头顶部),在其指定的字符的legalURLCharactersToBeEscaped参数会被无论如何逃脱(由于是在URL中的非法).您可能想要检查一下,尽管为安全起见并直接指定要转义的字符可能更好.

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


Dan*_*Ray 5

NSString *encodedString = [myString stringByAddingPercentEscapesUsingEncoding:NSASCIIStringEncoding];
Run Code Online (Sandbox Code Playgroud)

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

注意 - 新字符串将是autorelease'd,所以当你完成它时不要在它上面调用release.

  • 结果仍然相同,没有变化. (2认同)

Ene*_*nso 5

遵循 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)
Run Code Online (Sandbox Code Playgroud)

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