在Objective-C中使用Mime编码 – 单词解析

OS X或iOS是否提供了解析MIME编码字的API? 这些可爱的琴弦:

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

或者,是否有一个已知的开源库来执行此操作?

我拿了@ NickolayO。的答案 ,用QSSt​​rings添加了base-64支持,并使用componentsSeparatedByString: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 

以下是引用可打印版本的代码(Mime Encoded-word可以是quoted-printable或base-64编码)。 对于base64编码,你应该做同样的事情,用base64-decoding代替quoted-printable解码。 可能这段代码需要一些测试。 此外,它仅支持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; }