2008-11-10 2 views
102

Есть несколько способов удалить HTML tags из NSString в Cocoa.Удалить HTML-теги из NSString на iPhone

One way предназначен для рендеринга строки в NSAttributedString, а затем для получения выделенного текста.

Another way должен использовать 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 [ >>>>>>>>>>>> ]]> 
+0

Вы можете добавить немного логики, чтобы принять цитаты и апостроф во внимание ... CDATA займет немного больше работы, но вся суть в том, что HTML-теги неизвестные могут быть проигнорированы анализатор; если вы рассматриваете ВСЕ теги как неизвестные, тогда вы должны просто получить необработанный текст. – 2008-11-10 17:44:33

+0

Я хотел бы прокомментировать, что хорошее (но основное) регулярное выражение, безусловно, не сломается на ваших примерах. Конечно, нет, если вы можете гарантировать хорошо сформированный XHTML. Я знаю, что вы сказали, что не можете, но мне интересно, почему ;-) – Jake 2009-10-09 12:54:24

+1

Существует ** Хороший ответ ** на этот вопрос. [Сгладить HTML с помощью Objective c] (http://rudis.net/content/2009/01/21/flatten-html-content-ie-strip-tags-cocoaobjective-c) – vipintj 2010-07-09 09:12:37

ответ

305

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

Я это объявленным как кошка egory os NSString.

+0

Я полный новичок в разработке iPhone, но могу ли я спросить, как вы это используете? – James 2012-04-26 14:29:08

2

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

7

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

-3

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

+0

Это точный набор комментариев, с которыми я связан в моем вопросе, в качестве примера того, что бы не сработало. – lfalin 2008-11-14 03:59:19

4

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

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


заменяется ничем ... что нежелательно. – Nishant 2013-09-03 23:03:25

0

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

+26

Ради бога, не используйте Три20 для чего-либо. Самая раздутая и плохая прокомментированная структура. – kompozer 2012-01-20 15:45:20

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

4
#import "RegexKitLite.h" 

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

Эта 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 th у технически не XML.

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

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

0

Расширение это больше от m.kocikowski-х и ответы Dan Джея с большим количеством объяснений для новых bies

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 Я хочу, чтобы лишить теги.

2

Это модернизация м.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 
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:@""]; 
} 
1

Далее принятый ответ, но вместо категории, это просто вспомогательный метод с переданной строки в него. (Спасибо 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; 
} 
4
NSAttributedString *str=[[NSAttributedString alloc] initWithData:[trimmedString dataUsingEncoding:NSUTF8StringEncoding] options:@{NSDocumentTypeDocumentAttribute: NSHTMLTextDocumentType, NSCharacterEncodingDocumentAttribute: [NSNumber numberWithInt:NSUTF8StringEncoding]} documentAttributes:nil error:nil]; 
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; 
} 
0

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

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

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

Интерфейс:

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

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

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

}

Смежные вопросы