2009-05-07 8 views
4

Ich bin für eine RegEx Suche entweder die erste [n] Wörter in einem Absatz oder zurück, wenn der Absatz weniger als [n] Worte, die komplette Absatz zurückgegeben .RegEx benötigen Absatz oder erste n Worte zurück

Zum Beispiel unter der Annahme, ich brauche, höchstens die ersten 7 Worte:

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

Ich würde erhalten:

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

Und das gleiche RegEx auf einem Absatz, das weniger als die angeforderte Anzahl der Wörter:

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

einfach zurückkehren würde:

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

Mein Versuch, das Problem ergab folgende RegEx:

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

Dies ist jedoch nur das erste Wort gibt - "Eins". Es funktioniert nicht. Ich denke der .*? (Nach dem \ w + \ b) Probleme verursacht.

Wohin gehe ich falsch? Kann jemand eine RegEx präsentieren, die funktioniert?

FYI, ich bin mit Regex-Engine .Net 3.5 (via C#)

Vielen Dank

Antwort

7

OK, komplett neu bearbeiten die neue „spec“ bestätigen :)

Ich bin ziemlich sicher, Sie nicht, dass mit einer regex tun können. Das beste Tool ist definitiv ein HTML-Parser. Die nächstgelegene ich mit regulären Ausdrücken ist ein zweistufiger Ansatz zu bekommen.

Zunächst isolieren jeden Inhalt des Absatzes mit:

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

Sie müssen RegexOptions.Singleline festlegen, ob die Absätze über mehrere Zeilen erstrecken kann.

Dann wird in einem nächsten Schritt, iterieren Ihre Spiele über und wenden Sie den folgenden regulären Ausdruck einmal auf jedes Spiel der Group[1].Value:

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

, dass die ersten sieben Elemente durch Leerzeichen/Tabs/Zeilenumbrüche und ignoriert jede getrennt passen nach Interpunktion oder Non-Word-Zeichen.

ABER es behandelt eine durch Leerzeichen getrennte Markierung als eines dieser Elemente, d. e. in

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

wird es nur bis six zusammenpassen. Ich schätze, dass es im Regex nicht anders geht.

+0

Das ist perfekt - Prost! Ich weiß, dass es nie verschachtelte p Tags geben wird, so RegEx ist eine gute Passform. –

+0

Danke für Ihre Bemühungen - ich schätze es sehr (und danke, dass Sie das Versehen mit meiner ursprünglichen "Spezifikation" aufgezeigt haben) –

0
  1. einen HTML-Parser verwenden Sie den ersten Absatz zu bekommen, seine Struktur Abflachung (dh Dekorieren entfernen HTML-Tags innerhalb des Absatzes).
  2. Suchen Sie die Position des n-ten Leerzeichen.
  3. Nehmen Sie den Teil von 0 auf diese Position.

edit: entfernte ich die Regex Vorschlag für Schritt 2 und 3, da sie (dank der Kommentator) falsch war. Außerdem muss die HTML-Struktur abgeflacht werden.

+0

In einer Zeichenklasse entspricht \ b einem Backspace-Zeichen. Außerdem scheint sich die Problemdefinition geändert zu haben, seit Sie dies gepostet haben. \ w und \ W werden es nicht schneiden. –

0

Ich hatte das gleiche Problem und kombinierte ein paar Stack Overflow-Antworten in diese Klasse. Es verwendet das HtmlAgilityPack, das ein besseres Werkzeug für den Job ist. Aufruf:

Words(string html, int n) 

Um n Wörter

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(); 
     } 



    } 
} 

Frohe Weihnachten zu bekommen!