2009-05-07 7 views
4

Je suis à la recherche d'un RegEx pour retourner les [n] premiers mots d'un paragraphe ou, si le paragraphe contient moins de [n] mots, le paragraphe complet est retourné .Besoin de RegEx pour retourner le premier paragraphe ou les premiers mots

Par exemple, en supposant que j'ai besoin, au plus, les 7 premiers mots:

<p>one two <tag>three</tag> four five, six seven eight nine ten.</p><p>ignore</p> 

Je reçois:

one two <tag>three</tag> four five, six seven 

Et même RegEx sur un paragraphe contenant moins de la demande nombre de mots:

<p>one two <tag>three</tag> four five.</p><p>ignore</p> 

reviendriez simplement:

one two <tag>three</tag> four five. 

Ma tentative le problème a donné lieu à l'expression rationnelle suivante:

^(?:\<p.*?\>)((?:\w+\b.*?){1,7}).*(?:\</p\>) 

Cependant, cela renvoie juste le premier mot - « un ». Ça ne marche pas. Je pense que le .*? (après le \ w + \ b) provoque des problèmes.

Où est-ce que je me trompe? Quelqu'un peut-il présenter un RegEx qui fonctionnera?

Pour votre information, j'utilise le moteur regex .Net 3.5 (via C#)

Un grand merci

Répondre

7

OK, re-edit complète de reconnaître la nouvelle "spec" :)

Je suis sûr que vous ne pouvez pas le faire avec un regex. Le meilleur outil est certainement un analyseur HTML. Le plus proche que je peux obtenir avec regexes est une approche en deux étapes.

Tout d'abord, isoler le contenu de chaque paragraphe avec:

<p>(.*?)</p> 

Vous devez définir RegexOptions.Singleline si les paragraphes peuvent couvrir plusieurs lignes.

Puis, dans une étape suivante, itérer sur vos matchs et appliquer la regex suivante une fois sur Group[1].Value de chaque match:

((?:(\S+\s+){1,6})\w+) 

qui correspondent aux sept premiers éléments séparés par des espaces/onglets/retour à la ligne, sans tenir compte des signes de ponctuation ou caractères non-mots.MAIS il traitera une étiquette séparée par des espaces comme l'un de ces éléments, à savoir: i e. dans

One, two three <br\> four five six seven 

il correspondra seulement jusqu'à six. Je suppose que sur le plan du regex, il n'y a pas moyen de contourner ça.

+0

C'est parfait - Cheers! Je sais qu'il n'y aura jamais de balises p imbriquées, donc RegEx est un bon ajustement. –

+0

Merci pour vos efforts - je l'apprécie vraiment (et merci d'avoir souligné l'oubli avec mon "spec" d'origine) –

0
  1. Utilisez un analyseur HTML pour obtenir le premier paragraphe, aplatir sa structure (c.-à retirer la décoration Balises HTML dans le paragraphe).
  2. Recherchez la position du nième caractère d'espace.
  3. Prenez la sous-chaîne de 0 à cette position.

modifier: Je retiré la proposition regex pour l'étape 2 et 3, car il a eu tort (grâce à l'intervenant). En outre, la structure HTML doit être aplatie.

+0

A l'intérieur d'une classe de caractères, \ b correspond à un caractère de retour arrière. En outre, la définition du problème semble avoir été modifiée depuis que vous l'avez affichée; \ w et \ W ne vont pas le couper. –

0

J'ai eu le même problème et j'ai combiné quelques réponses Stack Overflow dans cette classe. Il utilise le HtmlAgilityPack qui est un meilleur outil pour le travail. Appel:

Words(string html, int n) 

Pour obtenir n mots

using HtmlAgilityPack; 
using System; 
using System.Collections.Generic; 
using System.Linq; 
using System.Text; 
using System.Threading.Tasks; 


namespace UmbracoUtilities 
{ 
    public class Text 
    { 
     /// <summary> 
     /// Return the first n words in the html 
     /// </summary> 
     /// <param name="html"></param> 
     /// <param name="n"></param> 
     /// <returns></returns> 
     public static string Words(string html, int n) 
     { 
     string words = html, n_words; 

     words = StripHtml(html); 
     n_words = GetNWords(words, n); 

     return n_words; 
     } 


     /// <summary> 
     /// Returns the first n words in text 
     /// Assumes text is not a html string 
     /// http://stackoverflow.com/questions/13368345/get-first-250-words-of-a-string 
     /// </summary> 
     /// <param name="text"></param> 
     /// <param name="n"></param> 
     /// <returns></returns> 
     public static string GetNWords(string text, int n) 
     { 
     StringBuilder builder = new StringBuilder(); 

     //remove multiple spaces 
     //http://stackoverflow.com/questions/1279859/how-to-replace-multiple-white-spaces-with-one-white-space 
     string cleanedString = System.Text.RegularExpressions.Regex.Replace(text, @"\s+", " "); 
     IEnumerable<string> words = cleanedString.Split().Take(n + 1); 

     foreach (string word in words) 
      builder.Append(" " + word); 

     return builder.ToString(); 
     } 


     /// <summary> 
     /// Returns a string of html with tags removed 
     /// </summary> 
     /// <param name="html"></param> 
     /// <returns></returns> 
     public static string StripHtml(string html) 
     { 
     HtmlDocument document = new HtmlDocument(); 
     document.LoadHtml(html); 

     var root = document.DocumentNode; 
     var stringBuilder = new StringBuilder(); 

     foreach (var node in root.DescendantsAndSelf()) 
     { 
      if (!node.HasChildNodes) 
      { 
      string text = node.InnerText; 
      if (!string.IsNullOrEmpty(text)) 
       stringBuilder.Append(" " + text.Trim()); 
      } 
     } 

     return stringBuilder.ToString(); 
     } 



    } 
} 

Joyeux Noël!

Questions connexes