Как добавить атрибут к первому тегу P с использованием регулярного выражения PHP?

WordPress объединяет сообщения в этом формате:

<h2>Some header</h> <p>First paragraph of the post</p> <p>Second paragraph of the post</p> etc. 

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

Цель состоит в том, чтобы получить приведенный выше код:

 <h2>Some header</h> <p class="first">First paragraph of the post</p> <p>Second paragraph of the post</p> 

У меня это до сих пор, но он даже не работает (ошибка: «preg_replace () [function.preg-replace]: Неизвестный модификатор ']'")

 $output=preg_replace('<p[^>]*>', '<p class="first">', $content); 

Я не могу использовать мета-селектор CSS3, потому что мне нужно поддерживать IE6, и я не могу применить мета-селектор первой строки (это тот, который поддерживает IE6) в родительском контейнере, потому что он попадет в H2 вместо первый П.

Возможно, вам будет проще и надежнее использовать парсер HTML, такой как этот . HTML, как известно, трудно анализировать достоверно (технически, невозможно) с помощью регулярных выражений, и синтаксический анализатор предоставит вам очень простое средство поиска интересующих вас узлов. На первой странице документа есть вкладка с надписью «Как изменить HTML-элементы ".

Две правильные возможности:

  1. Сделайте это в Javascript. Например, используя jQuery , это вопрос одной строки: $("h2").next().addClass("first")
  2. Используйте парсер HTML . Действительно, регулярное выражение не является хорошим инструментом для выполнения того, что вы хотите сделать . Поскольку загрузка всего HTML-парсера для этой цели является излишним, вам лучше использовать Javascript.

Неправильный путь

Конечно, чтобы ответить на вопрос, вот лучший способ, который я не могу придумать, чтобы сделать это с регулярным выражением. Хотя, я не рекомендую.

 preg_replace('#(</h2>\s*<p[^>]*)>#im', '$1 class="first">', '<h2>Some header</h> <p>First paragraph of the post</p> <p>Second paragraph of the post</p> '); 

Что мы делаем:

  • используя preg_replace, поэтому мы можем использовать расширенное regexp для замены кода;
  • используя флаг «m» и «i», поэтому регулярное выражение не беспокоится о разрыве строки или случае;
  • используя </h2>\s* для соответствия закрывающим «h2» тегам и всем разрывам пробелов / строк;
  • используя *<p[^>]* для соответствия тегу «p» и его текущим атрибутам;
  • используя скобки, чтобы сохранить это;
  • используя «$ 1» для замены, чтобы заменить согласованную строку, которую мы сохраняем;
  • добавление класса и закрытие «>».

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

Из и, кстати, у вас <h2>...</h> вместо <h2>...</h2> . Я не знаю, это опечатка, но я так и думал. Замените в регулярном выражении соответственно, если это не так.

Проблема в том, что первый символ регулярного выражения в функции preg_* принимается за разделитель модификатора. Вам нужно что-то вроде:

 $output = preg_replace('~<p\b([^>]*)>~', '<p class="first" \1>', $content, 1); 

Это также возвращает любые дополнительные атрибуты, которые могут иметь <p> .

В целом, однако, это более чистое отношение к селекторам CSS и резервному обеспечению JS для IE.

EDIT: добавлен лимит замены и разрыв слов.

в этом конкретном случае регулярное решение будет довольно простым

 echo preg_replace('~</h2>\s*<p~', "$0 class='first'", $html); 

Прочитав ответы, некоторые из них будут работать, но у всех есть недостатки либо использования внешней библиотеки синтаксического анализа, либо, возможно, соответствия меток, отличных от тега P, а также соответствия его атрибутам.

Я закончил использование этого решения с функцией str_replace_once отсюда :

 str_replace_once('<p>', '<p class="first">', $content); 

Достаточно просто и работает так, как предполагалось. Вот полный фрагмент кода WordPress для фильтрации первого абзаца всякий раз, когда вызывается вызов the_content ():

 add_filter('the_content', 'first_p_style'); function first_p_style($content) { $output=str_replace_once('<p>', '<p class="first">', $content); return ($output); } 

Спасибо за ответы на все вопросы!