preg_replace только ВНЕШНИЕ теги? (мы не говорим о полном «разборе html», просто немного уценки)

Каков самый простой способ применить выделение некоторого текста, исключая текст внутри тегов OCCASIONAL "‹...>"?

ПОЯСНЕНИЕ: я хочу, чтобы существующие теги были СОХРАНЕНЫ!

$t = 
preg_replace(
  "/(markdown)/",
  "<strong>$1</strong>",
"This is essentially plain text apart from a few html tags generated with some
simplified markdown rules: <a href=markdown.html>[see here]</a>");

Что должно отображаться как:

«По сути, это обычный текст, за исключением нескольких тегов html, сгенерированных с помощью некоторых упрощенных правил markdown: см. здесь"

... НО НЕ ИСПОЛЬЗУЙТЕ текст внутри тега привязки (например, <a href=markdown.html> ).

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


person ajo    schedule 05.01.2011    source источник
comment
Почему бы просто не найти все теги и не заменить их уникальным идентификатором (или автоматически увеличивающимся числом с * в начале. Затем запустить отметку preg_replace, а затем запустить str_replace, чтобы вернуть их все обратно.   -  person Jason    schedule 05.01.2011
comment
Почему в выводе выделена уценка? Потому что это произошло в параметре тега a?   -  person TJHeuvel    schedule 05.01.2011
comment
Связано: Выделение ключевых слов в абзаце   -  person Gumbo    schedule 05.01.2011


Ответы (6)


На самом деле, это работает нормально:

<?php
$item="markdown";
$t="This is essentially plain text apart from a few html tags generated 
with some simplified markdown rules: <a href=markdown.html>[see here]</a>";

//_____1. apply emphasis_____
$t = preg_replace("|($item)|","<strong>$1</strong>",$t);

// "This is essentially plain text apart from a few html tags generated 
// with some simplified <strong>markdown</strong> rules: <a href=
// <strong>markdown</strong>.html>[see here]</a>"

//_____2. remove emphasis if WITHIN opening and closing tag____
$t = preg_replace("|(<[^>]+?)(<strong>($item)</strong>)([^<]+?>)|","$1$3$4",$t);

// this preserves the text before ($1), after ($4) 
// and inside <strong>..</strong> ($2), but without the tags ($3)

// "This is essentially plain text apart from a few html tags generated
// with some simplified <strong>markdown</strong> rules: <a href=markdown.html>
// [see here]</a>"

?>

Строка типа $item="odd|string" вызовет некоторые проблемы, но я все равно не буду использовать такую ​​строку... (вероятно, требуется htmlentities(...) или тому подобное...)

person ajo    schedule 05.01.2011

Вы можете разделить строку на части tag‍/‍без тегов, используя preg_split:

$parts = preg_split('/(<(?:[^"\'>]|"[^"<]*"|\'[^\'<]*\')*>)/', $str, -1, PREG_SPLIT_DELIM_CAPTURE);

Затем вы можете перебирать части, пропуская каждую четную часть (т. е. части tag), и применять к ней замену:

for ($i=0, $n=count($parts); $i<$n; $i+=2) {
    $parts[$i] = preg_replace("/(markdown)/", "<strong>$1</strong>", $parts[$i]);
}

В конце соберите все обратно с помощью implode:

$str = implode('', $parts);

Но учтите, что это действительно не лучшее решение. Вам лучше использовать правильный парсер HTML, такой как библиотека PHP DOM. См., например, эти связанные вопросы:

person Gumbo    schedule 05.01.2011

Вы можете разбить свою строку на массив в каждом '‹' или '>', используя preg_split(), затем перебрать этот массив и заменить только в записях, не начинающихся с '>'. После этого вы объединяете свой массив в строку, используя implode().

person Simon    schedule 05.01.2011

Это регулярное выражение должно удалять все открывающие и закрывающие теги HTML: /(<[.*?]>)+/

Вы можете использовать его с preg_replace следующим образом:

$test = "Hello <strong>World!</strong>";
$regex = "/(<.*?>)+/";


$result = preg_replace($regex,"",$test);
person TJHeuvel    schedule 05.01.2011
comment
Я должен был уточнить: я хочу, чтобы существующие теги были сохранены! (см. правку выше) - person ajo; 05.01.2011
comment
Извините, я запутался. Вы хотели бы выделить весь текст, который не находится в элементе html? - person TJHeuvel; 05.01.2011

на самом деле это не очень эффективно, но мне помогло

$your_string = '...';

$search = 'markdown';
$left = '<strong>';
$right = '</strong>';

$left_Q = preg_quote($left, '#');
$right_Q = preg_quote($right, '#');
$search_Q = preg_quote($search, '#');
while(preg_match('#(>|^)[^<]*(?<!'.$left_Q.')'.$search_Q.'(?!'.$right_Q.')[^>]*(<|$)#isU', $your_string))
  $your_string = preg_replace('#(^[^<]*|>[^<]*)(?<!'.$left_Q.')('.$search_Q.')(?!'.$right_Q.')([^>]*<|[^>]*$)#isU', '${1}'.$left.'${2}'.$right.'${3}', $your_string);

echo $your_string;
person Floern    schedule 05.01.2011

Сначала замените любую строку после тега, но заставьте свою строку после тега:

$t=preg_replace("|(>[^<]*)(markdown)|i",'$1<strong>$2</strong>',"<null>$t");

Затем удалите принудительный тег:

$show=preg_replace("|<null>|",'',$show);

person Sergi Mayordomo    schedule 16.01.2020