RegEx для удаления возврата каретки между <p>тегами - PullRequest
1 голос
/ 22 октября 2009

Я поставил себя в тупик, пытаясь выяснить, как удалить возврат каретки между тегами <p>. (Технически мне нужно заменить их пробелами, а не удалять их.)

Вот пример. Я использовал знак доллара $ в качестве маркера возврата каретки.

<p> Ac nec <strong> приостановка, дибибус. </strong> Nulla taciti curabitur enim hendrerit. $
Ante ornare phasellus Tellus vivamus dictumst dolor aliquam imperdiet lectus. $
Nisl nullam sodales, tincidunt dictum dui eget, gravida anno. Монтес Конваллис $
Aipiscing, Aenean Hac Litora. Ridiculus, ut concquat curae, amet. Nostra $
Phasellus ridiculus class interdum justo. <em> Pharetra urna est hac </em> laoreet, magna. $
Porttitor purus purus, quis rutrum turpis. Монтес Нетус нибх Орнаре Потенци Квам $
учебный класс. Natoque nec proin sapien augue curae, elementum. </p>

Как показывает пример, между тегами <p> могут быть и другие теги. Поэтому я ищу регулярное выражение для замены всех этих возвратов каретки пробелами, но не касаюсь каких-либо возвратов каретки вне тегов <p>.

Любая помощь очень ценится. Спасибо!

Ответы [ 7 ]

4 голосов
/ 22 октября 2009

Решение с одним регулярным выражением здесь в принципе невозможно. Если вы абсолютно настаиваете на том, чтобы не использовать анализатор HTML, и вы можете рассчитывать на то, что ваши входные данные будут правильно сформированы и предсказуемы, тогда вы можете написать простой лексер, который выполнит эту работу (и я могу предоставить пример кода) - но он все еще не очень хорошая идея:)

Для справки:

3 голосов
/ 22 октября 2009

Стандартный ответ: не пытайтесь обрабатывать HTML (или SGML или XML) с помощью регулярного выражения. Используйте правильный парсер.

2 голосов
/ 22 октября 2009

Регулярные выражения особенно непригодны для решения проблем типа «сбалансированных скобок», даже если люди настаивают на том, чтобы их там запихнуть (и некоторые реализации - например, я имею в виду очень недавние выпуски Perl - попробуйтесотрудничать с этим широко распространенным заблуждением, расширяя и расширяя «регулярные выражения» хорошо за пределы определения CS; -).

Если вам не приходится иметь дело с вложением, это удобно выполнимопри двухпроходном подходе - захватите каждый абзац, например, <p>.*?</p> (возможно, с круглыми скобками для группировки), затем выполните подстановку в каждом абзаце, определенном таким образом.

1 голос
/ 22 октября 2009
[\r\n]+(?=(?:[^<]+|<(?!/?p\b))*</p>)

Первая часть соответствует одному или нескольким разделителям строк любого типа (\n, \r\n или \r). Остальная часть - это запрос, который пытается сопоставить все, вплоть до следующего закрывающего тега </p>, но если он сначала находит открывающий тег <p>, сопоставление завершается неудачей.

Обратите внимание, что это регулярное выражение можно очень легко одурачить, например, комментариями SGML, <script> элементами или простым старым искаженным HTML. Кроме того, я предполагаю, что ваш вкус регулярных выражений поддерживает позитивные и негативные взгляды. Это довольно безопасное предположение в наши дни, но если регулярное выражение не работает для вас, нам нужно точно знать, какой язык или инструмент вы используете.

0 голосов
/ 22 октября 2009

Это «почти достаточно» решение для лексинга, обещанное в моем другом ответе, чтобы набросать, как это можно сделать. Он делает нерешительную попытку справиться с атрибутами, но не серьезно. Он также не пытается справиться с не закодированным «<» в атрибутах. Это относительно незначительные ошибки, и он обрабатывает вложенные P-теги, но, как описано в комментариях, он совершенно не может обработать случай, когда кто-то <em>не закрывает P, потому что мы не можем сделать это без глубокое понимание HTML. Учитывая, насколько распространенной практикой является , можно объявить этот код «почти бесполезным». :)

#!/usr/bin/perl
use strict;
use warnings;

while ($html !~ /\G\Z/cg) {
  if ($html =~ /\G(<p[^>]*>)/cg) {
    $output .= $1;
    $in_p ++;
  } elsif ($html =~ m[\G(</p>)]cg) {
    $output .= $1;
    $in_p --; # Woe unto anyone who doesn't provide a closing tag.
    # Tag soup parsers are good for this because they can generate an
    # "artificial" end to the P when they find an element that can't contain
    # a P, or the end of the enclosing element. We're not smart enough for that.
  } elsif ($html =~ /\G([^<]+)/cg) {
    my $text = $1;
    $text =~ s/\s*\n\s*/ /g if $in_p;
    $output .= $text;
  } elsif ($html =~ /\G(<)/cg) {
    $output .= $1;
  } else {
    die "Can't happen, but not having an else is scary!";
  }
}
0 голосов
/ 22 октября 2009

Я думаю, что это должно работать так:

  1. получить весь абзац (текст между

    и

    ) из тела
  2. создать копию этого абзаца
  3. в копии заменить \ n пробелом
  4. в параграфе body body с измененной копией

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

Некоторый код на Python:

rx = re.compile(r'(<p>.*?</p>)', re.IGNORECASE | re.MULTILINE | re.DOTALL)

def get_paragraphs(body):
    paragraphs = []
    body_copy = body
    rxx = rx.search(body_copy)
    while rxx:
        paragraphs.append(rxx.group(1))
        body_copy = body_copy[rxx.end(1):]
        rxx = rx.search(body_copy)
    return paragraphs

def replace_paragraphs(body):
    paragraphs = get_paragraphs(body)
    for par in paragraphs:
        par_new = par.replace('\n', ' ')
        body = body.replace(par, par_new)
    return body

def main():
    new_body = replace_paragraphs(BODY)
    print(new_body)

main() 
0 голосов
/ 22 октября 2009

Просто используйте '\n', но убедитесь, что вы включили регулярное выражение с несколькими строками.

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