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

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

Одним из способов является преобразование строки в NSAttributedString а затем захват визуализированного текста.

Другой способ – использовать метод NSXMLDocument'sobjectByApplyingXSLTString для применения преобразования XSLT которое это делает.

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

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

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

  B"> <!--  --> if (ac) >>>>>>>>>>> ]]> 

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

Эта категория NSString использует NSXMLParser для точного удаления любых тегов HTML из NSString . Это один файл .m и .h который можно легко включить в ваш проект.

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

Затем вы удалите html , выполнив следующие действия:

Импортировать заголовок:

 #import "NSString_stripHtml.h" 

А затем вызовите stripHtml:

 NSString* mystring = @"Hello 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 simple"; [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 = @"bla bla"; NSString *stringWithoutHTML = [hstmString stringByReplacingOccurrencesOfRegex:myregex withString:@""]; 

не забудьте включить это в свой код: #import «RegexKitLite.h» вот ссылка для загрузки этого API: http://regexkit.sourceforge.net/#Downloads

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

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

 -(void)myMethod { NSString* htmlStr = @"html"; 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 использует регулярное выражение для поиска всех совпадающих тегов, делает копию исходной строки и, наконец, удаляет все tags, итерации по ним в обратном порядке. Это более эффективно, потому что:

  • Регулярное выражение инициализируется только один раз.
  • Используется единственная копия исходной строки.

Это достаточно хорошо для меня, но решение с использованием NSScanner может быть более эффективным.

Как и принятый ответ, это решение не затрагивает все случаи границ, запрашиваемые @lfalin. Для этого потребуется гораздо более дорогостоящий синтаксический анализ, который, скорее всего, не нужен.

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

 - (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:@""]; } 
 #import "RegexKitLite.h" string text = [html stringByReplacingOccurrencesOfRegex:@"<[^>]+>" withString:@""] 

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

  NSString *myText = [webView stringByEvaluatingJavaScriptFromString:@"document.documentElement.textContent"]; 
 NSAttributedString *str=[[NSAttributedString alloc] initWithData:[trimmedString dataUsingEncoding:NSUTF8StringEncoding] options:@{NSDocumentTypeDocumentAttribute: NSHTMLTextDocumentType, NSCharacterEncodingDocumentAttribute: [NSNumber numberWithInt:NSUTF8StringEncoding]} documentAttributes:nil error:nil]; 

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

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

.час

 + (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, нет? Прокрутите всю строку и скопируйте все, что не заключено в <> 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 

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

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

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

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

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

.час

 @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 из classа категории, который вы только что создали, например

 #import "NSString+NAME_OF_CATEGORY.h" 

3 # Вызов метода.

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

результатом является NSString. Я хочу удалить tags.

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

Вот быстрая версия:

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

Еще один способ:

Интерфейс:

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

}

Быстрая версия @ m.kocikowski Ответ:

 extension String { func isEmptyHTMLContent() -> Bool { var r = Range(self.startIndex..]+>", options: .regularExpression) { r = range str = str.replacingCharacters(in: r, with: "") } str = str.trimmingCharacters(in: NSCharacterSet.whitespacesAndNewlines) return str.isEmpty } } 

PS: Это работает для меня

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

  • objective-C: Как получить адрес маршрутизатора?
  • Какова стоимость использования автореферата в cocoa?
  • Как сделать ImageView UITableViewCell фиксированным, даже когда изображение меньше
  • Воспроизведение музыки в фоновом режиме с помощью AVAudioplayer
  • iOS HTTP-запрос в фоновом режиме
  • Получение списка файлов в каталоге с глобусом
  • Понимание подсчета ссылок с помощью Cocoa и Objective-C
  • UITableViewCell расширяется по клику
  • Как написать таймер в Objective-C?
  • Собственное использование приложения делегата приложения iPhone
  • Как я смогу удалить объекты из NSMutableArray?
  • Давайте будем гением компьютера.