Skip to content

Instantly share code, notes, and snippets.

@xslim
Created March 2, 2011 14:32
Show Gist options
  • Star 2 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save xslim/851018 to your computer and use it in GitHub Desktop.
Save xslim/851018 to your computer and use it in GitHub Desktop.
HTML to NSAttributedString
//
// NSAttributedString+fromHTML.m
// Berlingske
//
// Created by Taras Kalapun on 18.08.10.
// Copyright (c) 2010 Ciklum. All rights reserved.
//
#import "NSAttributedString+fromHTML.h"
@implementation NSAttributedString (fromHTML)
static BOOL underlineFlag = NO;
static BOOL boldFlag = NO;
static BOOL italicFlag = NO;
static CGFloat size = 18.0;
static NSString *linkString;
- (void)setCurrentAttributes:(NSMutableAttributedString *)attrString;
{
UIFont *nFont = [UIFont fontWithName:@"LucidaBright" size:size];
UIFont *bFont = [UIFont fontWithName:@"LucidaBright-Demi" size:size];
UIFont *iFont = [UIFont fontWithName:@"LucidaBright-Demi" size:size];
UIFont *biFont = [UIFont fontWithName:@"LucidaBright-Demi" size:size];
NSRange range;
range.location = 0;
range.length = [attrString length];
UIFont *font;
//NSLog(@"setting attributes - b:%d, i:%d, u:%d", boldFlag, italicFlag, underlineFlag);
if (boldFlag && italicFlag) {
font = biFont;
} else if (boldFlag) {
font = bFont;
} else if (italicFlag) {
font = iFont;
} else {
font = nFont;
}
//font = [font fontWithSize:size];
CTFontRef ctFont = CTFontCreateWithName((CFStringRef)font.fontName, font.pointSize, NULL);
/*
[attrString addAttribute:(NSString *)kCTFontAttributeName
value:(id)ctFont
range:range];
*/
NSMutableDictionary *attrDict;
attrDict = [NSMutableDictionary dictionaryWithCapacity:0];
[attrDict setObject:(id)ctFont forKey:(NSString *)kCTFontAttributeName];
[attrDict setObject:[NSNumber numberWithBool:underlineFlag] forKey:(NSString *)kCTUnderlineStyleAttributeName];
//if (linkString) [attrDict setObject:linkString forKey:NSLinkAttributeName];
[attrString addAttributes:attrDict range:range];
}
- (NSAttributedString *)initWithHTML:(NSString *)htmlString;
{
//NSLog(@"initWithHTML: %@", htmlString);
NSMutableAttributedString *attributedString;
NSRange range;
NSScanner *htmlScanner;
NSMutableString *strippedString;
boldFlag = NO;
italicFlag = NO;
underlineFlag = NO;
NSDictionary *keywordDictionary = [[NSDictionary alloc] initWithObjectsAndKeys:
@"&quot", @"\"",
@"&amp", @"&",
@"&lt", @"<",
@"&gt", @">",
nil];
strippedString = [NSMutableString stringWithCapacity:[htmlString length]];
htmlScanner = [NSScanner scannerWithString:htmlString];
while (![htmlScanner isAtEnd]) {
NSString *token;
[htmlScanner scanUpToCharactersFromSet:[NSCharacterSet whitespaceAndNewlineCharacterSet] intoString:&token];
[htmlScanner scanCharactersFromSet:[NSCharacterSet whitespaceAndNewlineCharacterSet] intoString:NULL];
[strippedString appendFormat:@"%@ ", token];
}
attributedString = [[[NSMutableAttributedString alloc] init] autorelease];
htmlScanner = [NSScanner scannerWithString:strippedString];
while (![htmlScanner isAtEnd]) {
NSString *firstPass, *tagString, *newString;
NSScanner *keywordScanner;
NSCharacterSet *openTagSet;
NSCharacterSet *closeTagSet;
NSMutableAttributedString *newAttributedString;
openTagSet = [NSCharacterSet characterSetWithCharactersInString:@"<"];
closeTagSet = [NSCharacterSet characterSetWithCharactersInString:@">"];
newAttributedString = [[[NSMutableAttributedString alloc] init] autorelease];
if ([htmlScanner scanUpToCharactersFromSet:openTagSet intoString:&firstPass]) {
keywordScanner = [NSScanner scannerWithString:firstPass];
while (![keywordScanner isAtEnd]) {
NSString *keyword = nil;
BOOL knownTag = NO;
NSCharacterSet *keywordTag;
NSEnumerator *keyEnum;
keywordTag = [NSCharacterSet characterSetWithCharactersInString:@"&"];
keyEnum = [[keywordDictionary allKeys] objectEnumerator];
[keywordScanner scanUpToCharactersFromSet:keywordTag intoString:&newString];
[newAttributedString appendAttributedString:[[[NSAttributedString alloc] initWithString:newString]autorelease]];
while (![keywordScanner isAtEnd] && (keyword = [keyEnum nextObject]))
if ([keywordScanner scanString:keyword intoString:NULL]) {
[newAttributedString appendAttributedString:[[[NSAttributedString alloc] initWithString:[keywordDictionary objectForKey:keyword]]autorelease]];
knownTag = YES;
}
if (!knownTag && [keywordScanner scanCharactersFromSet:keywordTag intoString:&newString])
[newAttributedString appendAttributedString:[[[NSAttributedString alloc] initWithString:newString]autorelease]];
}
[self setCurrentAttributes:newAttributedString];
[attributedString appendAttributedString:newAttributedString];
}
// Either we hit a '<' or we're at the end of the text.
if (![htmlScanner isAtEnd]) {
[htmlScanner scanCharactersFromSet:openTagSet intoString:NULL];
[htmlScanner scanUpToCharactersFromSet:closeTagSet intoString:&tagString];
[htmlScanner scanCharactersFromSet:closeTagSet intoString:NULL];
tagString = [tagString lowercaseString];
if ([tagString hasPrefix:@"a "]) {
range = [tagString rangeOfString:@"\""];
if (range.length) {
tagString = [tagString substringFromIndex:NSMaxRange(range)];
range = [tagString rangeOfString:@"\""];
linkString = [tagString substringToIndex:range.location];
} else if ((range = [tagString rangeOfString:@"="]).length) {
linkString = [tagString substringFromIndex:NSMaxRange(range)];
} else
linkString = nil;
[linkString retain];
} else if ([tagString isEqual:@"/a"]) {
[linkString release];
linkString = nil;
} else if ([tagString isEqual:@"b"] || [tagString isEqual:@"strong"])
boldFlag = YES;
else if ([tagString isEqual:@"/b"] || [tagString isEqual:@"/strong"])
boldFlag = NO;
else if ([tagString isEqual:@"h2"] || [tagString isEqual:@"h3"]) {
boldFlag = YES;
[attributedString appendAttributedString:[[[NSAttributedString alloc] initWithString:@"\n\n"]autorelease]];
} else if ([tagString isEqual:@"/h2"] || [tagString isEqual:@"/h3"]) {
boldFlag = NO;
[attributedString appendAttributedString:[[[NSAttributedString alloc] initWithString:@"\n\n"]autorelease]];
} else if ([tagString isEqual:@"i"] || [tagString isEqual:@"em"] || [tagString isEqual:@"cite"])
italicFlag = YES;
else if ([tagString isEqual:@"/i"] || [tagString isEqual:@"/em"] || [tagString isEqual:@"/cite"])
italicFlag = NO;
else if ([tagString isEqual:@"u"])
underlineFlag = YES;
else if ([tagString isEqual:@"/u"])
underlineFlag = NO;
else if ([tagString isEqual:@"p"])
[attributedString appendAttributedString:[[[NSAttributedString alloc] initWithString:@"\n\n"]autorelease]];
else if ([tagString isEqual:@"br"] || [tagString isEqual:@"br /"])
[attributedString appendAttributedString:[[[NSAttributedString alloc] initWithString:@"\n"]autorelease]];
else if ([tagString isEqual:@"/font"])
size = 12.0;
else if ([tagString hasPrefix:@"font size="] || [tagString hasPrefix:@"font size ="]) {
float foo;
if (sscanf([tagString UTF8String], "font size = +%f", &foo) == 1)
size += foo + 9;
else if (sscanf([tagString UTF8String], "font size = %f", &foo) == 1)
size = foo + 9;
}
}
}
range.location = 0;
range.length = [attributedString length];
[keywordDictionary release];
return [self initWithAttributedString:attributedString];
//return attributedString;
}
@end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment