Удалить HTML-tags из NSString на iPhone
Существует несколько способов удалить HTML tags
из NSString
в Cocoa
.
Одним из способов является преобразование строки в NSAttributedString
а затем захват визуализированного текста.
Другой способ – использовать метод NSXMLDocument's
– objectByApplyingXSLTString
для применения преобразования XSLT
которое это делает.
- NSArray слабых ссылок (__unsafe_unretained) для объектов под ARC
- Какую строку формата я использую в миллисекундах в строках даты на iPhone?
- UIScrollView не прокручивается после обновления до iOS7 / xcode 5
- Изменение цвета фона в UIAlertView?
- Как изменить заголовок кнопки «Назад» на панели навигации
К сожалению, iPhone не поддерживает NSAttributedString
или NSXMLDocument
. Слишком много краевых случаев и искаженных HTML
документов, чтобы я чувствовал себя комфортно с помощью регулярных выражений или NSScanner
. У кого-нибудь есть решение?
Одно из предложений заключалось в том, чтобы просто искать открывающие и закрывающие tags символов, этот метод не будет работать, за исключением очень тривиальных случаев.
Например, эти случаи (из главы Perl Cookbook по тому же вопросу) нарушили бы этот метод:
B"> <!-- --> if (ac) >>>>>>>>>>> ]]>
- Масштабирование MKMapView для подгонки аннотаций?
- UIPageViewController не возвращает никаких распознавателей жестов в iOS 6
- Как resize NSImage
- Использование MPMediaItems с AVAudioPlayer
- UISwitch в ячейке UITableView
- Установка UIDatePicker в таблицу UIActionSheet
- Как получить размер NSString
- Как передать объект с помощью NSNotificationCenter
Быстрое и «грязное» (удаляет все между <и>) решением, работает с 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/. Обратите внимание на комментарии, в которых предлагаются другие решения.