at_yasu's blog

ロード的なことを

NSStringをURLDecode/URLEncode

NSString型の文字列をURLDecode/URLDecodeするように、機能拡張したカテゴリクラス。


Encodeは文字通り、[a-zA-Z0-9/\-_.]文字列以外*1のを%xxに変換する。てか、CFURL~を使って返しているだけ。

Decodeは%xxをバイナリーに変換する。何かぱっと探しても簡単に変換する方法が見つからなかったので、PHPのURLDecodeから拝借。

@interface NSString (NSString)
- (NSDictionary*) decodeURLDictionary;
- (NSString*) decodeURL;
- (NSString*) URLEncode;
@end


static int HexFromChar(const char*s)
{
    int val,c;
    c = ((unsigned char*)s)[0];
    if (isupper(c)) c = tolower(c);
    val = (c >= '0' && c <= '9' ? c - '0' : c - 'a' + 10) * 16;
    
    c = ((unsigned char*)s)[1];
    if (isupper(c)) c = tolower(c);
    val += (c >= '0' && c <= '9' ? c - '0' : c - 'a' + 10);
    
    return val;
}

@implementation NSString (NSString)
-(NSString*) decodeURL
{
    NSMutableString *afterString = [NSMutableString string];
    const char *str_chars = [self cStringUsingEncoding: NSUTF8StringEncoding];
    int i = [self length];
    
    while (i--) {
        if (*str_chars == ' ') {
            [afterString appendString:@" "];
        }
        else if (*str_chars == '%' && isxdigit((int)*(str_chars + 1)) && isxdigit((int)*(str_chars+2)))
        {
            unsigned char buff = 0x00;
            buff = (char)HexFromChar((str_chars + 1));
            [afterString appendFormat:@"%c",buff,nil];
            i -= 2;
            str_chars += 2;
        }
        else
        {
            [afterString appendFormat:@"%c",*str_chars,nil];
        }
        str_chars ++;
    }
    
    return afterString;
}

- (NSUInteger) countOfChar:(char)c
{
    const char *str = [self cStringUsingEncoding:NSUTF8StringEncoding];
    int i = 0;
    NSUInteger counter = 0;
    
    for (i = 0; i < [self length]; i++) {
        if (str[i] == c)
            counter += 1;
    }
    return counter;
}

-(NSDictionary*) decodeURLDictionary
{
    NSString *decodeString = [self description];
    NSMutableDictionary* dict = [[NSMutableDictionary alloc] initWithCapacity:[decodeString countOfChar:'&']+1];
    NSArray *AmpSplit = [decodeString componentsSeparatedByString:@"&"];
    
    for (NSString *inWord in AmpSplit) {
        NSArray *equalSplit = [inWord componentsSeparatedByString:@"="];
        [dict setObject:[(NSString*)[equalSplit objectAtIndex:1] decodeURL]
                 forKey:[(NSString*)[equalSplit objectAtIndex:0] decodeURL]];
    }
    return dict;
}

- (NSString*) URLEncode
{
    CFStringRef ref = CFURLCreateStringByAddingPercentEscapes(NULL, (CFStringRef)self, NULL, NULL, kCFStringEncodingUTF8);
    return (NSString*)ref;
}

@end

*1:[#?:]も%xxに変換するんだっけ?