从iPhone上的NSString中删除HTML标记

有几种不同的方法可以从CocoaNSString中删除HTML tags

一种方法是将字符串呈现为NSAttributedString ,然后获取呈现的文本。

另一种方法是使用NSXMLDocument's objectByApplyingXSLTString方法来应用XSLT转换。

不幸的是,iPhone不支持NSAttributedStringNSXMLDocument 。 有太多的边缘情况和格式不正确的HTML文档让我感觉舒服的使用正则表达式或NSScanner 。 有没有人有这个解决方案?

一个建议是简单地寻找打开和关闭标记字符,除了非常微不足道的情况外,这种方法将不起作用。

例如,这些案例(来自Perl Cookbook的关于同一主题的章节)将打破这种方法:

 <IMG SRC = "foo.gif" ALT = "A > B"> <!-- <A comment> --> <script>if (a<b && a>c)</script> <![INCLUDE CDATA [ >>>>>>>>>>>> ]]> 

快速和“脏”(消除<和>之间的所有内容)解决方案,适用于iOS> = 3.2:

 -(NSString *) stringByStrippingHTML { NSRange r; NSString *s = [[self copy] autorelease]; while ((r = [s rangeOfString:@"<[^>]+>" options:NSRegularExpressionSearch]).location != NSNotFound) s = [s stringByReplacingCharactersInRange:r withString:@""]; return s; } 

我有这个声明为一个类别的操作系统NSString。

这个NSString类使用NSXMLParserNSString准确地删除任何HTML标签。 这是一个单独的.m.h文件,可以很容易地包含在你的项目中。

https://gist.github.com/leighmcculloch/1202238

然后通过执行以下操作去除html

导入标题:

 #import "NSString_stripHtml.h" 

然后调用stripHtml:

 NSString* mystring = @"<b>Hello</b> World!!"; NSString* stripped = [mystring stripHtml]; // stripped will be = Hello World!! 

这也适用于格式错误的HTML ,技术上不是XML

 UITextView *textview= [[UITextView alloc]initWithFrame:CGRectMake(10, 130, 250, 170)]; NSString *str = @"This is <font color='red'>simple</font>"; [textview setValue:str forKey:@"contentToHTMLString"]; textview.textAlignment = NSTextAlignmentLeft; textview.editable = NO; textview.font = [UIFont fontWithName:@"vardana" size:20.0]; [UIView addSubview:textview]; 

这对我来说工作很好

用这个

 NSString *myregex = @"<[^>]*>"; //regex to remove any html tag NSString *htmlString = @"<html>bla bla</html>"; NSString *stringWithoutHTML = [hstmString stringByReplacingOccurrencesOfRegex:myregex withString:@""]; 

不要忘记在你的代码中包含这个:#import“RegexKitLite.h”这里是下载这个API的链接: http ://regexkit.sourceforge.net/#Downloads

看看NSXMLParser。 这是一个SAX风格的解析器。 您应该能够使用它来检测XML文档中的标签或其他不需要的元素,并忽略它们,仅捕获纯文本。

你可以像下面一样使用

 -(void)myMethod { NSString* htmlStr = @"<some>html</string>"; NSString* strWithoutFormatting = [self stringByStrippingHTML:htmlStr]; } -(NSString *)stringByStrippingHTML:(NSString*)str { NSRange r; while ((r = [str rangeOfString:@"<[^>]+>" options:NSRegularExpressionSearch]).location != NSNotFound) { str = [str stringByReplacingCharactersInRange:r withString:@""]; } return str; } 

这是比接受的答案更有效的解决方案:

 - (NSString*)hp_stringByRemovingTags { static NSRegularExpression *regex = nil; static dispatch_once_t onceToken; dispatch_once(&onceToken, ^{ regex = [NSRegularExpression regularExpressionWithPattern:@"<[^>]+>" options:kNilOptions error:nil]; }); // Use reverse enumerator to delete characters without affecting indexes NSArray *matches =[regex matchesInString:self options:kNilOptions range:NSMakeRange(0, self.length)]; NSEnumerator *enumerator = matches.reverseObjectEnumerator; NSTextCheckingResult *match = nil; NSMutableString *modifiedString = self.mutableCopy; while ((match = [enumerator nextObject])) { [modifiedString deleteCharactersInRange:match.range]; } return modifiedString; } 

上面的NSString类使用正则表达式来查找所有匹配的标签,复制原始字符串,最后通过以相反顺序遍历所有标签来移除所有标签。 这是更有效的,因为:

  • 正则表达式只被初始化一次。
  • 使用原始字符串的单个副本。

这对我来说足够好,但使用NSScanner的解决方案可能会更有效。

就像接受的答案一样,这个解决方案并没有解决@lfalin所要求的所有边界情况。 那些将需要更昂贵的解析,平均使用情况最有可能不需要。

如果要从网页(HTML文档)获取没有html标签的内容,请在UIWebViewDidfinishLoading 委托方法内使用此代码。

  NSString *myText = [webView stringByEvaluatingJavaScriptFromString:@"document.documentElement.textContent"]; 

没有循环(至少在我们这边):

 - (NSString *)removeHTML { static NSRegularExpression *regexp; static dispatch_once_t onceToken; dispatch_once(&onceToken, ^{ regexp = [NSRegularExpression regularExpressionWithPattern:@"<[^>]+>" options:kNilOptions error:nil]; }); return [regexp stringByReplacingMatchesInString:self options:kNilOptions range:NSMakeRange(0, self.length) withTemplate:@""]; } 
 NSAttributedString *str=[[NSAttributedString alloc] initWithData:[trimmedString dataUsingEncoding:NSUTF8StringEncoding] options:@{NSDocumentTypeDocumentAttribute: NSHTMLTextDocumentType, NSCharacterEncodingDocumentAttribute: [NSNumber numberWithInt:NSUTF8StringEncoding]} documentAttributes:nil error:nil]; 
 #import "RegexKitLite.h" string text = [html stringByReplacingOccurrencesOfRegex:@"<[^>]+>" withString:@""] 

我已经扩展了m.kocikowski的答案,并尝试使用一个NSMutableString更高效一些。 我也将其结构化为用于静态Utils类(我知道类别可能是最好的设计),并删除autorelease,以便在ARC项目中编译。

包括在这里,以防有人发现它有用。

。H

 + (NSString *)stringByStrippingHTML:(NSString *)inputString; 

.M

 + (NSString *)stringByStrippingHTML:(NSString *)inputString { NSMutableString *outString; if (inputString) { outString = [[NSMutableString alloc] initWithString:inputString]; if ([inputString length] > 0) { NSRange r; while ((r = [outString rangeOfString:@"<[^>]+>" options:NSRegularExpressionSearch]).location != NSNotFound) { [outString deleteCharactersInRange:r]; } } } return outString; } 

我会想象最安全的方式就是解析<> s,不是? 循环遍历整个字符串,并将不包含在<>中的任何内容复制到新字符串中。

这是m.kocikowski回答现代化删除空格:

 @implementation NSString (StripXMLTags) - (NSString *)stripXMLTags { NSRange r; NSString *s = [self copy]; while ((r = [s rangeOfString:@"<[^>]+>\\s*" options:NSRegularExpressionSearch]).location != NSNotFound) s = [s stringByReplacingCharactersInRange:r withString:@""]; return s; } @end 

以下是被接受的答案,而不是类别,它是传递给它的字符串的简单帮助方法。 (谢谢你m.kocikowski)

 -(NSString *) stringByStrippingHTML:(NSString*)originalString { NSRange r; NSString *s = [originalString copy]; while ((r = [s rangeOfString:@"<[^>]+>" options:NSRegularExpressionSearch]).location != NSNotFound) s = [s stringByReplacingCharactersInRange:r withString:@""]; return s; } 

如果您已经解析了一个XML并且不想再次解析这个内容,那么这个帖子真的很有用。

更新

旧链接不再有效。 在这里更新后

如果你愿意使用Three20框架 ,它在NSString上有一个类添加stringByRemovingHTMLTags方法。 请参阅Three20Core子项目中的NSStringAdditions.h。

从m.kocikowski's和Dan J的答案延伸更多的新手解释

1#首先,您必须创建Objective-C类别以使代码在任何类中都可用。

。H

 @interface NSString (NAME_OF_CATEGORY) - (NSString *)stringByStrippingHTML; @end 

.M

 @implementation NSString (NAME_OF_CATEGORY) - (NSString *)stringByStrippingHTML { NSMutableString *outString; NSString *inputString = self; if (inputString) { outString = [[NSMutableString alloc] initWithString:inputString]; if ([inputString length] > 0) { NSRange r; while ((r = [outString rangeOfString:@"<[^>]+>" options:NSRegularExpressionSearch]).location != NSNotFound) { [outString deleteCharactersInRange:r]; } } } return outString; } @end 

2#然后,只需导入刚刚创建的类别类的.h文件,例如

 #import "NSString+NAME_OF_CATEGORY.h" 

3#调用方法。

 NSString* sub = [result stringByStrippingHTML]; NSLog(@"%@", sub); 

结果是NSString我想剥离标签。

我有以下m.kocikowski接受的答案和修改是略有利用autoreleasepool清理所有由stringByReplacingCharactersInRange创建的临时字符串

在这个方法的注释中,它声明:/ *用指定的字符串替换范围内的字符,返回新的字符串。 * /

所以,根据你的XML的长度,你可能会创建一大堆新的autorelease字符串,直到下一个@autoreleasepool结束时才清理掉。 如果您不确定何时会发生这种情况,或者用户操作可能会重复触发此方法的多次调用,那么您可以将其封装在@autoreleasepool中。 这些甚至可以在可能的环路中嵌套和使用。

苹果对@autoreleasepool的引用声明:“如果你编写了一个循环来创建许多临时对象,你可以在循环中使用一个自动释放池块来在下一次迭代之前处理这些对象,在循环中使用一个自动释放池块有助于减少应用程序的最大内存占用。“ 我没有在循环中使用它,但至少这个方法现在清理完毕。

 - (NSString *) stringByStrippingHTML { NSString *retVal; @autoreleasepool { NSRange r; NSString *s = [[self copy] autorelease]; while ((r = [s rangeOfString:@"<[^>]+>" options:NSRegularExpressionSearch]).location != NSNotFound) { s = [s stringByReplacingCharactersInRange:r withString:@""]; } retVal = [s copy]; } // pool is drained, release s and all temp // strings created by stringByReplacingCharactersInRange return retVal; } 

另一种方法:

接口:

-(NSString *) stringByStrippingHTML:(NSString*)inputString;

履行

 (NSString *) stringByStrippingHTML:(NSString*)inputString { NSAttributedString *attrString = [[NSAttributedString alloc] initWithData:[inputString dataUsingEncoding:NSUTF8StringEncoding] options:@{NSDocumentTypeDocumentAttribute: NSHTMLTextDocumentType,NSCharacterEncodingDocumentAttribute: @(NSUTF8StringEncoding)} documentAttributes:nil error:nil]; NSString *str= [attrString string]; //you can add here replacements as your needs: [str stringByReplacingOccurrencesOfString:@"[" withString:@""]; [str stringByReplacingOccurrencesOfString:@"]" withString:@""]; [str stringByReplacingOccurrencesOfString:@"\n" withString:@""]; return str; } 

实现

cell.exampleClass.text = [self stringByStrippingHTML:[exampleJSONParsingArray valueForKey: @"key"]];

或简单

NSString *myClearStr = [self stringByStrippingHTML:rudeStr];

@ m.kocikowski更新的答案,适用于最新的iOS版本。

 -(NSString *) stringByStrippingHTMLFromString:(NSString *)str { NSRange range; while ((range = [str rangeOfString:@"<[^>]+>" options:NSRegularExpressionSearch]).location != NSNotFound) str = [str stringByReplacingCharactersInRange:range withString:@""]; return str; 

}

这里是迅捷版本:

 func stripHTMLFromString(string: String) -> String { var copy = string while let range = copy.rangeOfString("<[^>]+>", options: .RegularExpressionSearch) { copy = copy.stringByReplacingCharactersInRange(range, withString: "") } copy = copy.stringByReplacingOccurrencesOfString("&nbsp;", withString: " ") copy = copy.stringByReplacingOccurrencesOfString("&amp;", withString: "&") return copy } 

这里有一篇博客文章,讨论一些可用于剥离HTML的库http://sugarmaplesoftware.com/25/strip-html-tags/注意其他解决方案提供的注释&#x3002;