Il existe différentes manières de supprimer HTML tags
d'une NSString
dans Cocoa
.
Une façon consiste à rendre la chaîne en NSAttributedString
, puis à récupérer le texte rendu.
Une autre façon consiste à utiliser la méthode NSXMLDocument's
-objectByApplyingXSLTString
pour appliquer une transformation XSLT
qui le fait.
Malheureusement, l'iPhone ne prend pas en charge NSAttributedString
ou NSXMLDocument
. Il y a trop de cas Edge et de documents HTML
malformés pour que je me sente à l'aise d'utiliser regex ou NSScanner
. Est-ce que quelqu'un a une solution à cela?
Une suggestion a été de simplement rechercher les caractères de balises ouvrantes et fermantes, cette méthode ne fonctionnera pas, sauf dans des cas très triviaux.
Par exemple, ces cas (du chapitre de Perl Cookbook sur le même sujet) rompraient cette méthode:
<IMG SRC = "foo.gif" ALT = "A > B">
<!-- <A comment> -->
<script>if (a<b && a>c)</script>
<![INCLUDE CDATA [ >>>>>>>>>>>> ]]>
Une solution rapide et "sale" (supprime tout ce qui se trouve entre <et>), fonctionne avec 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;
}
J'ai cette déclaré en tant que catégorie os NSString.
Cette catégorie NSString
utilise la NSXMLParser
pour supprimer avec précision toutes les balises HTML
d'une NSString
. Il s’agit d’un fichier .m
et .h
qui peut être facilement intégré à votre projet.
https://Gist.github.com/leighmcculloch/1202238
Vous supprimez ensuite html
en procédant comme suit:
Importer l'en-tête:
#import "NSString_stripHtml.h"
Et appelez stripHtml:
NSString* mystring = @"<b>Hello</b> World!!";
NSString* stripped = [mystring stripHtml];
// stripped will be = Hello World!!
Cela fonctionne également avec HTML
malformé qui, techniquement, n'est pas XML
.
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];
fonctionne bien pour moi
utilisez ceci
NSString *myregex = @"<[^>]*>"; //regex to remove any html tag
NSString *htmlString = @"<html>bla bla</html>";
NSString *stringWithoutHTML = [hstmString stringByReplacingOccurrencesOfRegex:myregex withString:@""];
n'oubliez pas de l'inclure dans votre code: #import "RegexKitLite.h" voici le lien pour télécharger cette API: http://regexkit.sourceforge.net/#Downloads
Vous pouvez utiliser comme ci-dessous
-(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;
}
Jetez un coup d'œil à NSXMLParser. C'est un analyseur de style SAX. Vous devriez pouvoir l'utiliser pour détecter des balises ou d'autres éléments indésirables dans le document XML et les ignorer, en capturant uniquement du texte pur.
Voici une solution plus efficace que la réponse acceptée:
- (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 catégorie NSString
ci-dessus utilise une expression régulière pour rechercher toutes les balises correspondantes, crée une copie de la chaîne d'origine et supprime enfin toutes les balises en place en les parcourant dans l'ordre inverse. C'est plus efficace parce que:
Cela a bien fonctionné pour moi, mais une solution utilisant NSScanner
pourrait être plus efficace.
Comme la réponse acceptée, cette solution ne traite pas tous les cas de frontière demandés par @lfalin. Celles-ci nécessiteraient une analyse beaucoup plus coûteuse, dont le cas d'utilisation moyen n'a probablement pas besoin.
Sans boucle (au moins de notre côté):
- (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:@""];
}
Si vous souhaitez obtenir le contenu sans les balises HTML de la page Web (document HTML), utilisez ce code dans la méthode UIWebViewDidfinishLoading
delegate .
NSString *myText = [webView stringByEvaluatingJavaScriptFromString:@"document.documentElement.textContent"];
#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];
J'ai prolongé la réponse de m.kocikowski et j'ai essayé de la rendre un peu plus efficace en utilisant un NSMutableString. Je l'ai également structurée pour une utilisation dans une classe Utils statique (je sais qu'une catégorie est probablement la meilleure conception), et j'ai supprimé la libération automatique afin qu'elle soit compilée dans un projet ARC.
Inclus ici au cas où quelqu'un le jugerait utile.
.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;
}
ce qui suit est la réponse acceptée, mais au lieu de la catégorie, il s'agit d'une méthode d'assistance simple avec chaîne passée. (merci 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;
}
J'imagine que le moyen le plus sûr serait simplement d'analyser <> s, non? Parcourez toute la chaîne et copiez tout ce qui n’est pas compris entre <> dans une nouvelle chaîne.
C’est la modernisation de m.kocikowski answer qui supprime les blancs:
@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
Voici la version de Swift:
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
}
Si vous voulez utiliser Three20 framework , il a une catégorie sur NSString qui ajoute la méthode stringByRemovingHTMLTags. Voir NSStringAdditions.h dans le sous-projet Three20Core.
Étendre cela davantage des réponses de m.kocikowski et Dan J avec plus d'explications pour les débutants
1 # Vous devez d’abord créer objective-c-categories pour rendre le code utilisable dans n’importe quelle classe.
.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 # Importez ensuite le fichier .h de la classe de catégorie que vous venez de créer, par exemple.
#import "NSString+NAME_OF_CATEGORY.h"
3 # Appel de la méthode.
NSString* sub = [result stringByStrippingHTML];
NSLog(@"%@", sub);
résultat est NSString Je veux enlever les balises.
J'ai suivi la réponse acceptée par m.kocikowski et modifié est légèrement d'utiliser un autoreleasepool pour nettoyer toutes les chaînes temporaires créées par stringByReplacingCharactersInRange
Dans le commentaire de cette méthode, il indique:/* Remplace les caractères compris dans la plage par la chaîne spécifiée, en renvoyant la nouvelle chaîne . * /
Par conséquent, en fonction de la longueur de votre code XML, vous pouvez créer une énorme pile de nouvelles chaînes autorelease qui ne sont pas nettoyées jusqu'à la fin du prochain @autoreleasepool. Si vous ne savez pas quand cela peut se produire ou si une action de l'utilisateur peut déclencher à plusieurs reprises plusieurs appels à cette méthode auparavant, vous pouvez simplement résumer cela dans un @autoreleasepool. Ceux-ci peuvent même être imbriqués et utilisés dans des boucles si possible.
La référence d'Apple sur @autoreleasepool indique ceci ... "Si vous écrivez une boucle qui crée de nombreux objets temporaires, vous pouvez utiliser un bloc de pool de relâche automatique à l'intérieur de la boucle pour en disposer avant la prochaine itération. Utilisation d'un bloc de pool de relâchement automatique dans la boucle contribue à réduire l'encombrement maximal de la mémoire de l'application. " Je ne l'ai pas utilisé dans la boucle, mais au moins cette méthode se nettoie après elle-même maintenant.
- (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;
}
Une réponse mise à jour pour @ m.kocikowski qui fonctionne sur les versions récentes d'iOS.
-(NSString *) stringByStrippingHTMLFromString:(NSString *)str {
NSRange range;
while ((range = [str rangeOfString:@"<[^>]+>" options:NSRegularExpressionSearch]).location != NSNotFound)
str = [str stringByReplacingCharactersInRange:range withString:@""];
return str;
}