framework - Eliminar etiquetas HTML de un NSString en el iPhone
objective c vs swift (22)
Aquí está la versión rápida:
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
}
Hay un par de maneras diferentes de eliminar HTML tags
de un NSString
en Cocoa
.
Una forma es convertir la cadena en un NSAttributedString
y luego tomar el texto renderizado.
Otra forma es usar NSXMLDocument''s
método objectByApplyingXSLTString
- objectByApplyingXSLTString
para aplicar una transformación XSLT
que lo haga.
Desafortunadamente, el iPhone no es compatible con NSAttributedString
o NSXMLDocument
. Hay demasiados casos extremos y documentos HTML
mal formados para que me sienta cómodo al usar regex o NSScanner
. ¿Alguien tiene una solución para esto?
Una sugerencia ha sido simplemente buscar caracteres de apertura y cierre de etiqueta, este método no funcionará excepto en casos muy triviales.
Por ejemplo, estos casos (del capítulo Perl Cookbook sobre el mismo tema) romperían este método:
<IMG SRC = "foo.gif" ALT = "A > B">
<!-- <A comment> -->
<script>if (a<b && a>c)</script>
<![INCLUDE CDATA [ >>>>>>>>>>>> ]]>
Aquí hay una publicación de blog que analiza un par de bibliotecas disponibles para eliminar HTML http://sugarmaplesoftware.com/25/strip-html-tags/ Tenga en cuenta los comentarios donde se ofrecen otras soluciones.
Aquí hay una solución más eficiente que la respuesta aceptada:
- (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;
}
La categoría NSString
anterior usa una expresión regular para encontrar todas las etiquetas coincidentes, realiza una copia de la cadena original y finalmente elimina todas las etiquetas en su lugar al iterar sobre ellas en orden inverso. Es más eficiente porque:
- La expresión regular se inicializa solo una vez.
- Se usa una sola copia de la cadena original.
Esto funcionó lo suficientemente bien para mí, pero una solución que utiliza NSScanner
podría ser más eficiente.
Al igual que la respuesta aceptada, esta solución no aborda todos los casos de frontera solicitados por @lfalin. Se requeriría un análisis mucho más costoso que el caso de uso promedio muy probablemente no necesite.
Eche un vistazo a NSXMLParser. Es un analizador de estilo SAX. Debería poder usarlo para detectar etiquetas u otros elementos no deseados en el documento XML e ignorarlos, capturando solo texto puro.
Esta categoría NSString
utiliza NSXMLParser
para eliminar con precisión cualquier etiqueta HTML
de un NSString
. Este es un archivo .m
y .h
único que se puede incluir fácilmente en su proyecto.
https://gist.github.com/leighmcculloch/1202238
A continuación, tira html
haciendo lo siguiente:
Importar el encabezado:
#import "NSString_stripHtml.h"
Y luego llama a stripHtml:
NSString* mystring = @"<b>Hello</b> World!!";
NSString* stripped = [mystring stripHtml];
// stripped will be = Hello World!!
Esto también funciona con HTML
mal formado que técnicamente no es XML
.
Esta es la modernización de la respuesta m.kocikowski que elimina los espacios en blanco:
@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
Extendiendo esto más de las respuestas de m.kocikowski y Dan J con más explicación para los novatos
1 # Primero tienes que crear objective-c-categories para hacer que el código sea utilizable en cualquier clase.
.h
@interface NSString (NAME_OF_CATEGORY)
- (NSString *)stringByStrippingHTML;
@end
.metro
@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 # Luego solo importa el archivo .h de la clase de categoría que acabas de crear, p. Ej.
#import "NSString+NAME_OF_CATEGORY.h"
3 # Llamar al método.
NSString* sub = [result stringByStrippingHTML];
NSLog(@"%@", sub);
el resultado es NSString del que quiero quitar las etiquetas.
He seguido la respuesta aceptada por m.kocikowski y se ha modificado ligeramente para hacer uso de un autorreleasepool para limpiar todas las cadenas temporales creadas por stringByReplacingCharactersInRange
En el comentario para este método, indica, / * Reemplaza los caracteres en el rango con la cadena especificada, devolviendo una nueva cadena. * /
Por lo tanto, dependiendo de la longitud de su XML, puede estar creando una gran cantidad de cadenas de autorrelease nuevas que no se limpian hasta el final de la siguiente @autoreleasepool. Si no está seguro de cuándo puede suceder eso o si una acción del usuario podría desencadenar muchas llamadas repetidas veces a este método antes, puede finalizarlo en un @autoreleasepool. Incluso se pueden anidar y usar dentro de bucles siempre que sea posible.
La referencia de Apple en @autoreleasepool establece esto ... "Si escribe un bucle que crea muchos objetos temporales, puede usar un bloque de reserva de liberación automática dentro del bucle para deshacerse de esos objetos antes de la siguiente iteración. Uso de un bloque de agrupación de liberación automática en el bucle ayuda a reducir la huella de memoria máxima de la aplicación ". No lo he usado en el ciclo, pero al menos este método se limpia ahora.
- (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;
}
Le extendí la respuesta a m.kocikowski y traté de hacerlo un poco más eficiente usando un NSMutableString. También lo he estructurado para su uso en una clase de Utils estática (aunque sé que una categoría es probablemente el mejor diseño), y eliminé la liberación automática para que se compile en un proyecto de ARC.
Incluido aquí en caso de que alguien lo encuentre útil.
.h
+ (NSString *)stringByStrippingHTML:(NSString *)inputString;
.metro
+ (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;
}
Me imagino que la forma más segura sería analizar por <> s, ¿no? Recorra toda la cadena y copie todo lo que no esté en <> s a una nueva cadena.
Otra forma:
Interfaz:
-(NSString *) stringByStrippingHTML:(NSString*)inputString;
Implementación
(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;
}
Realización
cell.exampleClass.text = [self stringByStrippingHTML:[exampleJSONParsingArray valueForKey: @"key"]];
o simple
NSString *myClearStr = [self stringByStrippingHTML:rudeStr];
Puedes usar como abajo
-(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;
}
Si desea obtener el contenido sin las etiquetas html de la página web (documento HTML), utilice este código dentro del método delegado UIWebViewDidfinishLoading
.
NSString *myText = [webView stringByEvaluatingJavaScriptFromString:@"document.documentElement.textContent"];
Si está dispuesto a utilizar Three20 framework , tiene una categoría en NSString que agrega el método stringByRemovingHTMLTags. Ver NSStringAdditions.h en el subproyecto Three20Core.
Sin un bucle (al menos de nuestro lado):
- (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:@""];
}
Una respuesta actualizada para @ m.kocikowski que funciona en versiones recientes de iOS.
-(NSString *) stringByStrippingHTMLFromString:(NSString *)str {
NSRange range;
while ((range = [str rangeOfString:@"<[^>]+>" options:NSRegularExpressionSearch]).location != NSNotFound)
str = [str stringByReplacingCharactersInRange:range withString:@""];
return str;
}
Una solución rápida y "sucia" (elimina todo entre <y>), funciona con 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;
}
He declarado esto como una categoría os NSString.
siguiente es la respuesta aceptada, pero en lugar de la categoría, es un método simple de ayuda con cadena pasada a él. (gracias 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;
}
utilizar esta
NSString *myregex = @"<[^>]*>"; //regex to remove any html tag
NSString *htmlString = @"<html>bla bla</html>";
NSString *stringWithoutHTML = [hstmString stringByReplacingOccurrencesOfRegex:myregex withString:@""];
no olvide incluir esto en su código: #import "RegexKitLite.h" aquí está el enlace para descargar esta API: http://regexkit.sourceforge.net/#Downloads
#import "RegexKitLite.h"
string text = [html stringByReplacingOccurrencesOfRegex:@"<[^>]+>" withString:@""]
NSAttributedString *str=[[NSAttributedString alloc] initWithData:[trimmedString dataUsingEncoding:NSUTF8StringEncoding] options:@{NSDocumentTypeDocumentAttribute: NSHTMLTextDocumentType, NSCharacterEncodingDocumentAttribute: [NSNumber numberWithInt:NSUTF8StringEncoding]} documentAttributes:nil error:nil];
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];
esto es trabajo bien para mi