Regex игнорирует совпадения между тегами <script>
Извиняюсь, так как у меня очень мало знаний о Regex, и я даже не понимаю, что делает это регулярное выражение (я его не писал - source), кроме того, что он ищет определенный термин, чтобы он мог быть выделен.
Вот регулярное выражение:
/(\b$term|$term\b)(?!([^<]+)?>)/iu
Проблема в том, что мне нужно убедиться, что она не соответствует чему-либо между тегами <script>
и </script>
. Теперь я знаю, что существует множество вариантов использования тега script, но на самом деле все, что мне нужно, это игнорировать любой текст между <script
и /script>
с учетом возможных пробелов между script
и <
например < script
или /script >
.
Кто-нибудь может изменить его таким образом? Я буду уведомлять автора плагина, который написал этот reg-ex для включения в будущие выпуски.
Изменить: Вот функция, из которой она исходит:
function relevanssi_highlight_terms($excerpt, $query) {
$type = get_option("relevanssi_highlight");
if ("none" == $type) {
return $excerpt;
}
switch ($type) {
case "mark": // thanks to Jeff Byrnes
$start_emp = "<mark>";
$end_emp = "</mark>";
break;
case "strong":
$start_emp = "<strong>";
$end_emp = "</strong>";
break;
case "em":
$start_emp = "<em>";
$end_emp = "</em>";
break;
case "col":
$col = get_option("relevanssi_txt_col");
if (!$col) $col = "#ff0000";
$start_emp = "<span style='color: $col'>";
$end_emp = "</span>";
break;
case "bgcol":
$col = get_option("relevanssi_bg_col");
if (!$col) $col = "#ff0000";
$start_emp = "<span style='background-color: $col'>";
$end_emp = "</span>";
break;
case "css":
$css = get_option("relevanssi_css");
if (!$css) $css = "color: #ff0000";
$start_emp = "<span style='$css'>";
$end_emp = "</span>";
break;
case "class":
$css = get_option("relevanssi_class");
if (!$css) $css = "relevanssi-query-term";
$start_emp = "<span class='$css'>";
$end_emp = "</span>";
break;
default:
return $excerpt;
}
$start_emp_token = "*[/";
$end_emp_token = "\]*";
if ( function_exists('mb_internal_encoding') )
mb_internal_encoding("UTF-8");
$terms = array_keys(relevanssi_tokenize($query, $remove_stopwords = true));
$phrases = relevanssi_extract_phrases(stripslashes($query));
$non_phrase_terms = array();
foreach ($phrases as $phrase) {
$phrase_terms = array_keys(relevanssi_tokenize($phrase, false));
foreach ($terms as $term) {
if (!in_array($term, $phrase_terms)) {
$non_phrase_terms[] = $term;
}
}
$terms = $non_phrase_terms;
$terms[] = $phrase;
}
usort($terms, 'relevanssi_strlen_sort');
get_option('relevanssi_word_boundaries', 'on') == 'on' ? $word_boundaries = true : $word_boundaries = false;
foreach ($terms as $term) {
$pr_term = preg_quote($term, '/');
if ($word_boundaries) {
$excerpt = preg_replace("/(\b$pr_term|$pr_term\b)(?!([^<]+)?>)/iu", $start_emp_token . '\\1' . $end_emp_token, $excerpt);
}
else {
$excerpt = preg_replace("/($pr_term)(?!([^<]+)?>)/iu", $start_emp_token . '\\1' . $end_emp_token, $excerpt);
}
// thanks to http://pureform.wordpress.com/2008/01/04/matching-a-word-characters-outside-of-html-tags/
}
$excerpt = relevanssi_remove_nested_highlights($excerpt, $start_emp_token, $end_emp_token);
$excerpt = str_replace($start_emp_token, $start_emp, $excerpt);
$excerpt = str_replace($end_emp_token, $end_emp, $excerpt);
$excerpt = str_replace($end_emp . $start_emp, "", $excerpt);
if (function_exists('mb_ereg_replace')) {
$pattern = $end_emp . '\s*' . $start_emp;
$excerpt = mb_ereg_replace($pattern, " ", $excerpt);
}
return $excerpt;
}
Ответы
Ответ 1
Так как утверждения lookbehind должны быть исправлены по длине, вы не можете использовать их для поиска предыдущего тега <script>
где-то до искомого термина.
Итак, после того, как вы замените все вхождения искомого термина, вам понадобится второй проход, чтобы вернуть обратно те вхождения измененного термина, которые, как представляется, находятся внутри тега <script>
.
# provide some sample data
$excerpt = 'My name is bob!
And bob is cool.
<script type="text/javascript">
var bobby = "It works fine even if you already have tagged the term <em>bob</em> inside the script tag.";
alert(bobby);
var bob = 5;
</script>
Yeah, the word "bob" works fine.';
$start_emp_token = '<em>';
$end_emp_token = '</em>';
$pr_term = 'bob';
# replace everything (not in a tag)
$excerpt = preg_replace("/(\b$pr_term|$pr_term\b)(?!([^<]+)?>)/iu", $start_emp_token . '$1' . $end_emp_token, $excerpt);
# undo some of the replacements
$excerpt = preg_replace_callback('#(<script(?:[^>]*)>)(.*?)(</script>)#is',
create_function(
'$matches',
'global $start_emp_token, $end_emp_token, $pr_term;
return $matches[1].str_replace("$start_emp_token$pr_term$end_emp_token", "$pr_term", $matches[2]).$matches[3];'
),
$excerpt);
var_dump($excerpt);
Приведенный выше код производит следующий вывод:
string(271) "My name is <em>bob</em>!
And <em>bob</em> is cool.
<script type="text/javascript">
var bobby = "It works fine even if you already have tagged the term <em>bob</em> inside the script tag.";
alert(bobby);
var bob = 5;
</script>
Yeah, the word "<em>bob</em>" works fine."
Ответ 2
Самый точный подход заключается в следующем:
- Проведите анализ HTML с помощью собственного парсера HTML
- Игнорировать строки, которые находятся в тегах
<script>
.
Вы не хотите использовать синтаксический анализ HTML с регулярными выражениями. Здесь объяснение почему: http://htmlparsing.com/regexes.html
В конечном итоге это огорчит вас. Пожалуйста, взгляните на остальную часть http://htmlparsing.com/ для некоторых указателей, которые могли бы начать работу.
Ответ 3
Вы упомянули в комментарии, что было бы приемлемо удалить теги script перед выполнением поиска.
$data = preg_replace('/<\s*script.*?\/script\s*>/iu', '', $data);
Этот код может помочь в этом.
Ответ 4
Джордж, воскресив этот древний вопрос, потому что у него было простое решение, которое не упоминалось. Эта ситуация прямо из моего домашнего вопроса о том, что сопоставить (или заменить) шаблон, за исключением ситуаций s1, s2, s3 и т.д.
Вы хотите изменить следующее регулярное выражение, чтобы исключить что-либо между <script>
и </script>
:
(\bSOMETERM|SOMETERM\b)(?!([^<]+)?>)
Пожалуйста, простите меня за $term
с SOMETERM
, это для ясности, потому что $
имеет специальное значение в регулярном выражении.
Со всеми отказами относительно соответствия html в regex, чтобы исключить что-либо между <script>
и </script>
, вы можете просто добавить это в начало своего регулярного выражения:
<script>.*?</script>(*SKIP)(*F)|
поэтому регулярное выражение становится:
<script>.*?</script>(*SKIP)(*F)|(\bSOMETERM|SOMETERM\b)(?!([^<]+)?>)
Как это работает?
Левая часть ИЛИ (т.е. |
) соответствует полным тегам <script...</script>
, а затем сознательно терпит неудачу. Правая сторона соответствует тому, что вы были сопоставлены раньше, и мы знаем, что это правильный материал, потому что, если бы это было между тегами script, это провалилось.
Ссылка
Как сопоставить (или заменить) шаблон, за исключением ситуаций s1, s2, s3...