Удалить HTML-теги из NSString на iPhone

Существует несколько способов удалить HTML tags из NSString в Cocoa.

Один из способов - отобразить строку в NSAttributedString, а затем захватить визуализированный текст.

Другим способом является использование метода NSXMLDocument's - objectByApplyingXSLTString для применения преобразования XSLT, которое это делает.

К сожалению, iPhone не поддерживает NSAttributedString или NSXMLDocument. Слишком много краевых случаев и неправильных документов HTML для меня, чтобы чувствовать себя комфортно с помощью регулярного выражения или NSScanner. У кого-нибудь есть решение?

Одно из предложений заключалось в том, чтобы просто искать открывающие и закрывающие теги символов, этот метод не будет работать, за исключением очень тривиальных случаев.

Например, эти случаи (из главы Perl Cookbook по тому же вопросу) нарушили бы этот метод:

<IMG SRC = "foo.gif" ALT = "A > B">

<!-- <A comment> -->

<script>if (a<b && a>c)</script>

<![INCLUDE CDATA [ >>>>>>>>>>>> ]]>

Ответ 1

Быстрое и "грязное" (удаляет все между < и > ) решением, работает с 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.

Ответ 2

В этой категории 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.

Ответ 3

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

отлично работает для меня

Ответ 4

используйте этот

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

Ответ 5

Взгляните на NSXMLParser. Это синтаксический анализатор SAX. Вы должны иметь возможность использовать его для обнаружения тегов или других нежелательных элементов в документе XML и игнорировать их, захватывая только чистый текст.

Ответ 6

Вы можете использовать, как показано ниже

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

Ответ 7

Здесь более эффективное решение, чем принятый ответ:

- (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. Для этого потребуется гораздо более дорогостоящий синтаксический анализ, который, скорее всего, не понадобится среднему варианту использования.

Ответ 8

Без цикла (по крайней мере, на нашей стороне):

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

Ответ 9

#import "RegexKitLite.h"

string text = [html stringByReplacingOccurrencesOfRegex:@"<[^>]+>" withString:@""]

Ответ 10

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

Ответ 11

Если вы хотите получить контент без тэгов html с веб-страницы (HTML-документ), используйте этот код внутри метода UIWebViewDidfinishLoading делегировать.

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

Ответ 12

Я продлил ответ m.kocikowski и попытался сделать его более эффективным, используя NSMutableString. Я также структурировал его для использования в статическом классе Utils (я знаю, что Категория, вероятно, лучший дизайн) и удалил авторекламу, поэтому она компилируется в проекте ARC.

Включается здесь, если кто-либо сочтет это полезным.

.h

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

ого

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

Ответ 13

Я бы предположил, что самый безопасный способ - просто разобрать на < > s, no? Прокрутите всю строку и скопируйте все, что не заключено в < > s, в новую строку.

Ответ 14

Это модернизация ответа 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

Ответ 15

Ниже приведен принятый ответ, но вместо категории это простой вспомогательный метод со строкой, переданной в него. (спасибо м.коциковски)

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

Ответ 16

Это сообщение было действительно полезно, если вы уже проанализировали XML и не хотите снова разбирать содержимое.

Обновление

Старая ссылка больше не работает. Обновлено сообщение здесь

Ответ 17

Здесь быстрая версия:

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
}

Ответ 18

Если вы хотите использовать структуру 320, у нее есть категория в NSString, которая добавляет метод stringByRemovingHTMLTags. См. NSStringAdditions.h в подпроекте Three20Core.

Ответ 19

Расширение этого больше от m.kocikowski и Dan J дает больше объяснений для новичков

1 # Сначала вам нужно создать objective-c-categories, чтобы сделать код пригодным для использования в любом классе.

.h

@interface NSString (NAME_OF_CATEGORY)

- (NSString *)stringByStrippingHTML;

@end

ого

@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. Я хочу удалить теги из.

Ответ 20

Я следую принятому ответу 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;
}

Ответ 21

Другой способ:

Интерфейс:

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

Ответ 22

Обновленный ответ для @m.kocikowski, который работает в последних версиях iOS.

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

}

Ответ 23

Вот сообщение в блоге, в котором обсуждается несколько библиотек, доступных для удаления HTML http://sugarmaplesoftware.com/25/strip-html-tags/ Обратите внимание на комментарии, в которых предлагаются другие решения.