从iPhone上的NSString中删除HTML标签

问题描述 投票:104回答:22

有几种不同的方法可以从HTML tagsNSString中删除Cocoa

One way将字符串渲染为NSAttributedString,然后抓取渲染的文本。

Another way将使用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 objective-c iphone cocoa-touch nsstring
22个回答
307
投票

一个快速和“脏”(删除<和>之间的所有内容)解决方案,适用于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;
}

我将此声明为os NSString类别。


4
投票
NSAttributedString *str=[[NSAttributedString alloc] initWithData:[trimmedString dataUsingEncoding:NSUTF8StringEncoding] options:@{NSDocumentTypeDocumentAttribute: NSHTMLTextDocumentType, NSCharacterEncodingDocumentAttribute: [NSNumber numberWithInt:NSUTF8StringEncoding]} documentAttributes:nil error:nil];

3
投票

我已经扩展了m.kocikowski的答案,并试图通过使用NSMutableString使其更有效。我还将其结构化用于静态Utils类(我知道类别可能是最好的设计),并删除了自动释放,因此它在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; 
}

3
投票

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

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

2
投票

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


2
投票

这是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

2
投票

以下是接受的答案,但不是类别,而是传递给它的字符串的简单帮助方法。 (谢谢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;
}

1
投票

这是快速版本:

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
}

0
投票

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


0
投票

将此更多地从m.kocikowski和Dan J的答案中进一步扩展,并为新手提供更多解释

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

。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我想从中剥离标签。


0
投票

我已经按照m.kocikowski接受的答案进行了修改,稍微修改后使用autoreleasepool来清理stringByReplacingCharactersInRange创建的所有临时字符串

在该方法的注释中,它指出,/ *用指定的字符串替换范围内的字符,返回新的字符串。 * /

因此,根据XML的长度,您可能会创建大量新的自动释放字符串,这些字符串在下一个@autoreleasepool结束之前不会被清除。如果您不确定何时可能发生这种情况,或者用户操作可能会在此之前重复触发对此方法的多次调用,则可以将其包装在@autoreleasepool中。这些甚至可以嵌套并尽可能在循环中使用。

Apple对@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;
}

29
投票

这个NSString类别使用NSXMLParser准确地从HTML中删除任何NSString标签。这是一个单独的.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


0
投票

另一种方式:

接口:

-(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];


0
投票

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

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

}


-3
投票

这是一篇博客文章,讨论了几个可用于剥离HTML http://sugarmaplesoftware.com/25/strip-html-tags/的库。请注意提供其他解决方案的注释。


10
投票
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];

对我来说很好


8
投票

用这个

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


7
投票

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


7
投票

你可以使用如下

-(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;
 }

6
投票

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

- (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要求的所有边界案例。这些将需要更昂贵的解析,而平均用例很可能不需要。


5
投票

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

- (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:@""];
}

4
投票
#import "RegexKitLite.h"

string text = [html stringByReplacingOccurrencesOfRegex:@"<[^>]+>" withString:@""]
© www.soinside.com 2019 - 2024. All rights reserved.