web-dev-qa-db-fra.com

Supprimer les balises HTML d'une chaîne NSString sur l'iPhone

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 [ >>>>>>>>>>>> ]]>
104
lfalin

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. 

307
m.kocikowski

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.

29
Leigh McCulloch
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

8
Mohamed AHDIDOU

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;
 }
7
Kirtikumar A.

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.

7
Colin Barrett

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:

  • L'expression régulière est initialisée une seule fois.
  • Une seule copie de la chaîne d'origine est utilisée.

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.

6
hpique

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:@""];
}
5
Rémy

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"];
4
Biranchi
#import "RegexKitLite.h"

string text = [html stringByReplacingOccurrencesOfRegex:@"<[^>]+>" withString:@""]
4
Jim Liu
NSAttributedString *str=[[NSAttributedString alloc] initWithData:[trimmedString dataUsingEncoding:NSUTF8StringEncoding] options:@{NSDocumentTypeDocumentAttribute: NSHTMLTextDocumentType, NSCharacterEncodingDocumentAttribute: [NSNumber numberWithInt:NSUTF8StringEncoding]} documentAttributes:nil error:nil];
4
Pavan Sisode

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; 
}
3
Dan J

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;
}
2
tmr

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. 

2
Ben Gottlieb

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
2
digipeople

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("&nbsp;", withString: " ")
  copy = copy.stringByReplacingOccurrencesOfString("&amp;", withString: "&")
  return copy
}
1
JohnVanDijk

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.

0
jarnoan

É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.

0
Ashoor

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;
}
0
jcpennypincher

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;

}

0
Ahmed Awad