2008-11-13 6 views
8

Avant que quelqu'un ne me le demande, je ne fais aucune sorte de screenschraping. J'essaie d'analyser une chaîne html pour trouver un div avec un certain ID. Je ne peux pas pour la vie de moi obtenir cela pour travailler. L'expression suivante a fonctionné dans un cas, mais pas dans un autre. Je ne suis pas sûr si cela a à voir avec des éléments supplémentaires dans le code HTML ou non.Regex - Trouver le contenu de div par id avec divs imbriqués

<div\s*?id=(\""|&quot;|&#34;)content(\""|&quot;|&#34;).*?>\s*?(?>(?! <div\s*?> | </div>) | <div\s*?>(?<DEPTH>) | </div>(?<-DEPTH>) | .?)*(?(DEPTH)(?!))</div> 

Il est de trouver la première div id avec le droit correctement, mais il se ferme alors au premier div de fermeture, et non la div liées.

<div id="firstdiv">begining content<div id="content">some other stuff 
    <div id="otherdiv">other stuff here</div> 
    more stuff 
    </div> 
</div> 

Cela devrait ramener

<div id="content">some other stuff 
    <div id="otherdiv">other stuff here</div> 
    more stuff 
</div> 

, mais pour une raison quelconque, il n'est pas. Il est ramènerait:

<div id="content">some other stuff 
     <div id="otherdiv">other stuff here</div> 

Quelqu'un at-il une expression plus facile à gérer cette situation?

Pour clarifier, ceci est dans .NET, et j'utilise le mot-clé DEPTH. Vous pouvez trouver plus de détails here.

+0

upvoted - c'est une excellente question pour enseigner aux nouveaux programmeurs les limites de ce que les expressions régulières peuvent accomplir. – Cybis

+0

Peut-être pas en pur Reg. Exp. mais cela peut certainement être fait avec .net. Voir ma réponse. – pro3carp3

Répondre

5

Dans .NET, vous pouvez le faire:

(?<text> 
(<div\s*?id=(\"|&quot;|&\#34;)content(\"|&quot;|&\#34;).*?>) 

    (?> 
     .*?</div> 
    | 
     .*?<div (?>depth) 
    | 
     .*?</div> (?>-depth) 
)*) 
    (?(depth)(?!)) 
.*?</div> 

Vous devez utiliser l'option SingleLine. Voici un exemple utilisant la console:

using System; 
using System.Text.RegularExpressions; 

namespace Temp 
{ 
    class Program 
    { 
     static void Main() 
     { 
      string s = @" 
<div id=""firstdiv"">begining content<div id=""content"">some other stuff 
    <div id=""otherdiv"">other stuff here</div> 
    more stuff 
    </div> 
</div>"; 
      Regex r = new Regex(@"(?<text>(<div\s*?id=(\""|&quot;|&\#34;)" 
       + @"content(\""|&quot;|&\#34;).*?>)(?>.*?</div>|.*?<div " 
       + @"(?>depth)|.*?</div> (?>-depth))*)(?(depth)(?!)).*?</div>", 
       RegexOptions.Singleline); 
      Console.WriteLine("HTML:\n"); 
      Console.WriteLine(s); 
      Match m = r.Match(s); 
      if (m.Success) 
      { 
       Console.WriteLine("\nCaptured text:\n"); 
       Console.WriteLine(m.Groups[4]); 

      } 
      Console.ReadLine(); 
     } 
    } 
} 
+0

Laissez à Microsoft le soin de modifier la définition des langues normales. – Cybis

5

Demandez-vous une expression régulière permettant de suivre le nombre de balises DIV imbriquées dans une balise DIV? J'ai peur que ce ne soit pas possible avec des expressions régulières.

Vous pouvez utiliser une expression régulière pour obtenir l'index de la première balise DIV, puis faire une boucle sur les caractères de la chaîne, en commençant à cet index et en comptant le nombre de balises div ouvertes. Lorsque vous rencontrez un div-tag proche, et que le nombre est zéro, alors vous avez les index de début et de fin dans la chaîne qui contient la sous-chaîne que vous voulez.

+0

Je comprends qu'il existe des extensions récursives qui permettent cela, mais cela ne peut pas être fait dans une regex pure. –

0

Quel langage de programmation? Si c'est .Net et que vous êtes sûr que le html est bien formé, vous pouvez le charger dans un objet XmlDocument ou XDocument et y faire une requête xpath.

+0

... et il analyserait probablement plus vite que cette expression régulière. –

2

Cybis dit la vérité. Ce genre de choses tombe dans des langages sans contexte, qui sont plus puissants que les langages réguliers (le genre de choses couvertes par les expressions régulières). Il y a beaucoup de théorie de l'informatique en jeu, mais laissons de côté pour dire que toute langue digne de ce nom aura une bibliothèque pour ce genre de choses écrites que vous devriez probablement utiliser.

Questions connexes