Поиск, обработка и замена текста между тегами на PHP

Сегодня возникла задача обработки уведомлений по шаблону с ключевыми словами. К примеру “Здравствуйте [[name]]!”. Где name нужно заменить на имя пользователя в письме.

Нашел статью…

Сегодня я постараюсь объяснить как найти, обработать и заменить текст между тегами используя PHP функции. На первый взгляд простая задача, тем более в PHP есть специально предназначенные для этого функции, позволяющие использовать для поиска и замены регулярные выражения. Чтобы было проще разобраться, будем все делать на примерах. За основу возьмем абстрактный html код:

<xx>наташа</xx> ... <xx>даша</<xx>настя</

Здесь <xx> — представляет какой-то конкретный html тег, а троеточие — другие произвольные теги. Предлагаю постепенно начинать разбираться с возможностями PHP по работе со строками. Все пункты будем рассматривать на примерах.

Поиск текста функцией «preg_match_all»

Для поиска текста внутри тегов воспользуемся функцией «preg_match_all». Зададим маску поиска и посмотрим, что она возвращает в качестве результата.

$sContent "... <xx>наташа</xx> ... <xx>даша</xx> ... <xx>настя</xx> ..."preg_match_all'|<xx>(.+)</xx>|isU' $sContent 

  echo $arr"<br />"
  echo $arr//на выходе получаем://<xx>наташа</xx> <xx>даша</xx> <xx>настя</xx>//наташа даша настя

В нулевой разряд массива записались значения с тегами, а в первый – только текст между ними. Если требуется вывести все найденные результаты, то лучше всего использовать цикл foreach, его рассмотрим ниже, а пока немного информации про функцию preg_match_all.

Она возвращает либо «1», в случае нахождения в тексте соответствия с указанной маской или «0» если соответствий не найдено. В качестве параметров функция принимает маску поиска, строковую переменную в которой будет осуществляться поиск и переменную типа двухмерный массив, в который будут записываться найденные совпадения.

|<>(.+)</>|

Маска поиска текста между тегов обрамляется символом «|». Таких правил в маске может быть несколько. Для нашей задачи достаточно одного.

В правиле у нас содержатся теги, между которыми требуется заменить текст — «(.+)». Регулярное выражение указывает на то, что между ними может быть любое количество любых символов. Знак плюс означает что их должно быть больше нуля. То есть, если между тегами ничего нет, то результата никакого не получим. Если хотим найти даже те места, где между тегов нет никакого текста, то вместо плюса ставим знак звёздочки — «*». Директива «isU» обозначает регистронезависимый поиск в многострочном тексте кодировки «UTF-8».

Перебор найденных результатов в цикле «foreach»

Для вывода всех результатов поиска лучше всего воспользоваться циклом «foreach».

$sContent "... <xx>Наташа</xx> ... <xx>Марина</xx> ... <xx>Настя</xx> ..."preg_match_all'|<xx>(.+)</xx>|isU' $sContentforeach $value echo $value"<br/>"foreach $value echo $value

На выходе получаем тоже самое что и в предыдущем примере, зато теперь мы автоматизировали перебор массива и сократили код.

Отличие «preg_match» от «preg_match_all»

Разница заключается в том, что «preg_match» ищет только до первого совпадения с маской поиска. Как только что-то найдено, поиск останавливается. Так же разница в выдаваемом результате. «preg_match» возвращает одномерный массив. Вот пример.

preg_match'|<title>(.+?)</title>|isU' $sContentreturnreturnfalse

В этом случае нулевой элемент массива «$arr» содержит найденное совпадение вместе с тегами «title», а первый элемент – «$arr[1]» только текст между этими тегами. И не путайте, если в искомом коде несколько тегов «title», это не значит что остальные значения будут записаны в «$arr[2]» и так далее. В случае с «preg_match» поиск идет только до первого найденного совпадения, а элемент «$arr[2]» окажется не пуст, только если в маске указано несколько правил, но об этом в следующий раз.

Замена текста между тегами функцией «preg_replace»

Если требуется не просто найти, но ещё и произвести замену найденных элементов в строке, то на помощь приходит PHP функция «preg_replace».

Давайте заменим в нашем примере все имена между тегами на какое-то конкретное, например — «Оля».

$sContent "<xx>наташа</xx> ... <xx>даша</xx> ... <xx>настя</xx>"
$sContent  preg_replace'|(<xx>)(.+)(</xx>)|isU'"Оля"$sContent

Замена тегов, оставляя всё, что находится внутри

А теперь небольшой пример, показывающий как заменить определенные теги, сохранив при этом содержимое между ними. Допустим, надо изменить в html коде все «strong» на CSS форматирование.

$sContent "... <strong>Настя</strong> ..."

$sContent  preg_replace'|<strong(.*)strong>|isU''<span style="font-weight: bold;" $1span>' $sContent//на выходе получаем $sContent://... <span style="font-weight: bold;" >Настя</span> ...

Обработка и замена при помощи «preg_replace_callback»

А теперь переходим к самому интересному. Что делать, если нужно над найденным фрагметом произвести какие-то действия и только потом осуществить замену? Конечно же использовать «preg_replace_callback». Для примера рассмотрим как в именах сделать первую букву заглавной.

<html><head><metacharset"UTF-8"</head><body><?php 
$sContent "<xx>наташа</xx> ... <xx>даша</xx> ... <xx>настя</xx>"

echo htmlspecialchars$sContent"<br />"

$sContent  preg_replace_callback'|(<xx>)(.+)(</xx>)|iU'function$matches
	$matches mb_substrmb_strtoupper$matches'UTF-8''UTF-8'substr$matchesreturn $matches$matches$matches$sContent

echo htmlspecialchars$sContent?></body></html>

В качестве параметров мы передаём маску поиска, функцию с кодом обработки и строковую переменную в которой осуществляем поиск. Дополнительно могут быть заданы ещё два необязательных параметра. О них в следующем разделе статьи.

Переменная «$matches» это массив, содержащий элементы регулярного выражения. В нулевом элементе будет содержаться вся исходная строка, а в остальных — содержимое скобок.

Код обработки не буду описывать, отмечу что для замены первой буквы на заглавную я использую PHP функции для работы со строками в UTF-8 кодировке. Если у вас кодировка cp1251, то нужно отбросить префикс «mb_» и удалить последний параметр у функций.

ВНИМАНИЕ! Код в примере будет работать только при использовании PHP версии 5.3 и выше. Для более поздних версий требуется доработка.

Использование нумирации в заменах и другие продвинутые возможности

Теперь немного о продвинутых возможностях функции «preg_replace_callback». Ранее я упоминал что у неё есть два необязательных параметра. Первый (по умолчанию равен «-1») содержит максимальное количество замен, которое должна произвести функция. Второй — переменная, в которую будет записано количество произведенных замен.

$sContent  preg_replace_callback'|(<xx>)(.+)(</xx>)|iU'function$matches//тут код }$sContent$count

Задав эти два параметра в предыдущем примере, замена главной буквы будет произведена только у первых двух имён. Соответственно, переменная «$count» будет содержать — 2. Если установить первый дополнительный параметр в «-1», то «$count» будет — 3.

И в конце о том как узнать какая по счету замена происходит в данный момент. Это может потребоваться если появилась необходимость произвести замену между пятым и десятым найденным элементом строки или требуется для каких-то тегов прописать уникальные идентификаторы.

Для такой реализации может быть использована глобальная или статическая переменная. Использование глобальных переменных может быть отключено в PHP, поэтому рассмотрим пример со статической переменной. Присвоим всем тегам h2 уникальный идентификатор.

<?php
$str '<h2>Марина</h2> <b>Алёша</b> <h2>Наташа</h2> <h2>Катя</h2>' preg_replace_callback'|<h2>(.+)</h2>|iU'function$matchesstaticreturn'<h2 id="uniq-''">'$matches'</h2>'$count

echo $str' Количество замен: '$count?>

Объявляя статическую переменную нужно помнить что она сохраняет своё значение между вызовами функции, поэтому идеально подходит для решения нашей задачи.

ВНИМАНИЕ! Дополнительные параметры в «preg_replace_callback» появились начиная с PHP версии 5.1

Источник: http://realadmin.ru/coding/replace-between-tags.html

Ответить

Ваш адрес email не будет опубликован. Обязательные поля помечены *