Решение, которое подходит для вывода мнемоник, не применимо для случаев вывода листингов с html-кодом. У задачи появляются новые особенности.
<code html>
и перед закрывающим </code>
могут идти пробельные символы. Паттерн @<code.*?>(.*?)code>@
не учитывает этот момент.Иллюстрация работы итоговой функции.
1. Составить хороший пример, иллюстрирующий все тонкие моменты.
<code html>
и перед </code>
нет, html-тэга всего два открывающий и закрывающий.<code html><p>Обрамляющие тэги на одной строке с теми, что нужно экранировать. Нет вложенных тэгов.</p></code>
<code html>
<b>Закрывающий тэг</b> на одной строке с теми, что надо <em>экранировать</em>. Нет вложенных тэгов, но есть следующие друг за другом.</code>
<code html>
и <code>
отделены пробельными символами, листинг содержит несколько строк и вложенные тэги.<code html>
<ul><li>Первый пункт</li>
<li>Второй пункт</li></ul>
</code>
<code html>
находится на одной строке с экранируемым текстом, закрывающий отделен пробельным символом (перевод строки). В листинге встречаются мнемоники внутри html-тэгов и за их пределами, а также спецсимволы. Мнемоника должна отображаться в итоге в виде кода мнемоники, а спецсимвол должен отображаться спецсимволом.<code html><b>Попугаям — свободу!</b> А компании 'Horns & Hoofs' — хороших адвокатов.
</code>
2. Функция htmlentities(), увы, не вполне подходит. Нам нужна замена всего двух символов: <
на <
и &
на &
. Создадим свою функцию, которая будет выполнять эту задачу.
function changesymbols ($somecontent) {
preg_match_all("@\&@",$somecontent,$smatches); //собираем массив вхождений амперсанда
$nums=sizeof($smatches[0]); //считаем количество амперсандов в тексте
$somecontent=preg_replace("@\&@","&",$somecontent,$nums); //производим замену в $somecontent несколько раз, а именно $nums раз
preg_match_all("@\<@",$somecontent,$fmatches);
$nums=sizeof($fmatches[0]);
$somecontent=preg_replace("@\<@","<",$somecontent,$nums);
return $somecontent;
};
3. Выполняем замену с сохранением разбиения по строкам.
Посчитаем число отрывков исходного кода для экранирования.
$iteration=substr_count($content, "<code html");
Создадим цикл с нужным числом итераций.
Внутри цикла проверяем условие.
if ( preg_match("<co
de html>(.*?)</co
de>@s", $content, $matches)>0 ) {}
Здесь паттерн @<code html>(.*?)</code>@s
позволяет найти и те случаи, когда после открывающего тэга или перед закрывающим идёт пробельный символ. Можно было бы его записать ещё так: @(?|<code html>|<code html>\s)(.*?)(?|</code>|\s</code>)@
Далее перезаписываем вначале каждой итерации значение переменных: $difflines=''; $resultcode='';
С помощью функции preg_split()
разбиваем исходный текст по регулярному выражению символу новой строки, таким образом строки исходного текста записываются в массив.
Считаем количество строк.
Производим замену символов в каждой строке по отдельности, а потом измененную строку прибавляем конкатенацией к результирующей переменной $resultcode
.
В конце делаем замену тэгов <code html>
на <htmlcode>
, чтобы в следующей итерации внешнего цикла не обрабатывать этот текст вновь.
Для WordPress нужно отключить функцию автоматического добавления абзацев, чтобы функция работала корректно. Результат для WordPress выглядит так:
remove_filter('the_cont
ent', 'wpautop');
function true_code ($con
tent) {
if ( is_single() ) {
$iteration=substr_count($content, "<code html");
function changesymbols ($somecontent) {
preg_match_all("@\&@",$somecontent,$smatches);
$nums=sizeof($smatches[0]);
$somecontent=preg_replace("@\&@","&",$somecontent,$nums);
preg_match_all("@\<@",$somecontent,$fmatches);
$nums=sizeof($fmatches[0]);
$somecontent=preg_replace("@\<@","<",$somecontent,$nums);
return $somecontent;
};
for ($i=0; $i<$iteration; $i++) {
if ( preg_match("@<code html>(.*?)</code>@s", $content, $matches)>0 ) {
$difflines='';
$difflines=preg_split('#\n#', $matches[1]);
$difflines_size=sizeof($difflines);
$resultcode='';
for ($k=0; $k<$difflines_size; $k++) {
$difflines[$k]=changesymbols($difflines[$k]);
$resultcode.=$difflines[$k].'<br>';
};
$content=preg_replace("@<code html>(.*?)</code>@s", "<htmlcode>".$resultcode."</htmlcode>", $content, 1);
};
};
return $content;
} else return $content;
};
add_filter('the_content', 'true_code');
Для всех остальных случаев надо убрать первую, третью и последнюю строки.