OS X 或 iOS 是否提供 API 来解析MIME Encoded-Word?这些可爱的字符串:
=?iso-8859-1?Q?=A1Hola,_se=F1or!?=
或者,是否有一个已知的开源库可以做到这一点?
OS X 或 iOS 是否提供 API 来解析MIME Encoded-Word?这些可爱的字符串:
=?iso-8859-1?Q?=A1Hola,_se=F1or!?=
或者,是否有一个已知的开源库可以做到这一点?
我接受了@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
这是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;
}