3

OS X 或 iOS 是否提供 API 来解析MIME Encoded-Word?这些可爱的字符串:

=?iso-8859-1?Q?=A1Hola,_se=F1or!?=

或者,是否有一个已知的开源库可以做到这一点?

4

2 回答 2

2

我接受了@NickolayO. 的回答,使用QSStrings添加了 base-64 支持,并使用componentsSeparatedByString:and缩短了代码stringByReplacingOccurrencesOfString:withString:

我已经在GitHub 上提供了代码。为方便起见,这是一个片段:

@implementation NSString (MimeEncodedWord)

- (BOOL) isMimeEncodedWord
{
    return [self hasPrefix:@"=?"]  && [self hasSuffix:@"?="];
}

+ (NSString*) stringWithMimeEncodedWord:(NSString*)word
{ // Example: =?iso-8859-1?Q?=A1Hola,_se=F1or!?=
    NSArray *components = [word componentsSeparatedByString:@"?"];
    if (components.count < 5) return nil;

    NSString *charset = [components objectAtIndex:1];
    NSStringEncoding encoding = CFStringConvertEncodingToNSStringEncoding(CFStringConvertIANACharSetNameToEncoding((CFStringRef)charset)); // TODO: What happens if the encoding is invalid?

    NSString *encodingType = [components objectAtIndex:2];
    NSString *encodedText = [components objectAtIndex:3];
    if ([encodingType isEqualToString:@"Q"])
    { // quoted-printable
        encodedText = [encodedText stringByReplacingOccurrencesOfString:@"_" withString:@" "];
        encodedText = [encodedText stringByReplacingOccurrencesOfString:@"=" withString:@"%"];
        NSString *decoded = [encodedText stringByReplacingPercentEscapesUsingEncoding:encoding];
        return decoded;
    } else if ([encodingType isEqualToString:@"B"])
    { // base64
        NSData *data = [QSStrings decodeBase64WithString:encodedText];
        NSString *decoded = [[NSString alloc] initWithData:data encoding:encoding];
        return decoded;
    } else {
        NSLog(@"%@ is not a valid encoding (must be Q or B)", encodingType);
        return nil;
    }    
}

@end
于 2012-12-24T02:25:42.383 回答
1

这是quoted-printable 版本的代码(Mime Encoded-word 可以是quoted-printable 或base-64 编码)。对于 base64 编码,你应该做类似的事情,用 base64 解码替换引用打印解码。可能这段代码需要一些测试。此外,它仅支持 NSString 的编码。

- (NSString*) decodeMimeEncodedWord:(NSString*)word
{
    if (![word hasPrefix:@"=?"] || ![word hasSuffix:@"?="])
        return nil;

    int i = 2;
    while ((i < word.length) && ([word characterAtIndex:i] != (unichar)'?'))
        i++;

    if (i >= word.length - 4)
        return nil;

    NSString *encodingName = [word substringWithRange:NSMakeRange(2, i - 2)];
    NSStringEncoding encoding = CFStringConvertEncodingToNSStringEncoding(CFStringConvertIANACharSetNameToEncoding((CFStringRef)encodingName));
    // warning! can return 'undefined something' if encodingName is invalid or unknown

    NSString *encodedString;

    if ([[word substringWithRange:NSMakeRange(i + 1, 2)] isEqualToString:@"Q?"])
    {
        // quoted-printable
        encodedString = [word substringWithRange:NSMakeRange(i + 3, word.length - i - 5)];
        NSMutableData *binaryString = [[[NSMutableData alloc] initWithLength:encodedString.length] autorelease];
        unsigned char *binaryBytes = (unsigned char*)[binaryString mutableBytes];
        int j = 0;
        char h;     

        for (i = 0; i < encodedString.length; i++)
        {
            unichar ch = [encodedString characterAtIndex:i];
            if (ch == (unichar)'_')
                binaryBytes[j++] = ' ';
            else if (ch == (unichar)'=')
            {
                if (i >= encodedString.length - 2)
                    return nil;

                unsigned char val = 0;

                // high-order hex char
                h = [encodedString characterAtIndex:++i];
                if ((h >= '0') && (h <= '9'))
                    val += ((int)(h - '0')) << 4;
                else if ((h >= 'A') && (h <= 'F'))
                    val += ((int)(h + 10 - 'A')) << 4;
                else
                    return nil;
                // low-order hex char
                h = [encodedString characterAtIndex:++i];
                if ((h >= '0') && (h <= '9'))
                    val += (int)(h - '0');
                else if ((h >= 'A') && (h <= 'F'))
                    val += (int)(h + 10 - 'A');
                else
                    return nil;

                binaryBytes[j++] = val;             
            }
            else if (ch < 256)
                binaryBytes[j++] = ch;
            else
                return nil;
        }

        binaryBytes[++j] = 0;
        [binaryString setLength:j];

        NSString *result = [[NSString alloc] initWithCString:[binaryString mutableBytes] encoding:encoding];        
        // warning! can return 'undefined something' if encoding is invalid or unknown

        return result;
    }
    else if ([[word substringWithRange:NSMakeRange(i + 1, 2)] isEqualToString:@"B?"])
    {
        // base64-encoded       
        return nil;
    }
    else
        return nil;
}
于 2012-12-23T21:28:33.143 回答