Нужен RegEx для возврата первого абзаца или первых n слов - PullRequest
4 голосов
/ 07 мая 2009

Я ищу RegEx для возврата либо первых [n] слов в абзаце, либо, если абзац содержит меньше [n] слов, возвращается полный абзац.

Например, предполагая, что мне нужно, максимум, первые 7 слов:

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

Я бы получил:

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

И тот же RegEx для абзаца, содержащего меньше запрошенного количества слов:

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

Просто вернется:

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

Моя попытка решить проблему привела к следующему RegEx:

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

Однако, это возвращает только первое слово - «один». Не работает Я думаю .*? (после \ w + \ b) вызывает проблемы.

Куда я иду не так? Кто-нибудь может представить RegEx, который будет работать?

К вашему сведению, я использую движок Reg .Net 3.5 (через C #)

Большое спасибо

Ответы [ 3 ]

7 голосов
/ 07 мая 2009

ОК, завершите повторное редактирование, чтобы подтвердить новую «спецификацию»:)

Я почти уверен, что вы не можете сделать это с одним регулярным выражением. Самый лучший инструмент - это HTML-парсер. Самое близкое, что я могу получить с помощью регулярных выражений, - это двухэтапный подход.

Сначала выделите содержимое каждого абзаца с помощью:

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

Вам необходимо установить RegexOptions.Singleline, если абзацы могут занимать несколько строк.

Затем, на следующем шаге, итерируйте свои совпадения и примените следующее регулярное выражение один раз к Group[1].Value каждого матча:

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

Это будет соответствовать первым семи пунктам, разделенным пробелами / символами табуляции / переводами строки, игнорируя любые знаки препинания или неслова.

НО он будет рассматривать тег, разделенный пробелами, как один из этих элементов, т.е. е. в

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

будет соответствовать только до six. Я думаю, что с точки зрения регулярных выражений, нет никакого способа обойти это.

0 голосов
/ 25 декабря 2013

У меня была та же проблема, и я скомбинировал несколько ответов Stack Overflow в этом классе. Он использует HtmlAgilityPack, который является лучшим инструментом для работы. Звоните:

 Words(string html, int n)

Чтобы получить n слов

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



    }
}

С Рождеством!

0 голосов
/ 07 мая 2009
  1. Используйте синтаксический анализатор HTML для получения первого абзаца, выравнивая его структуру (т.е. удаляйте украшающие теги HTML внутри абзаца).
  2. Поиск позиции n-го символа пробела.
  3. Возьмите подстроку от 0 до этой позиции.

edit: Я удалил предложение регулярного выражения для шагов 2 и 3, так как оно было неверным (спасибо комментатору). Кроме того, HTML-структура должна быть сведена.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...