Regex игнорирует совпадения между тегами <script>

Я прошу прощения, поскольку у меня очень мало знаний о Regex, и я даже не понимаю, что делает это регулярное выражение (я не писал его – источник ), кроме того, что он ищет определенный термин, чтобы его можно было выделить.

Вот регулярное выражение:

/(\b$term|$term\b)(?!([^<]+)?>)/iu 

Проблема в том, что мне нужно убедиться, что она не соответствует чему-либо между тегами <script> и </script> . Теперь я знаю, что существует множество вариантов написания тега сценария, но на самом деле все, что мне нужно, это игнорировать любой текст между <script и /script> с учетом возможных пробелов между script и < like < 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; } 

Поскольку утверждения 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." 

Наиболее точный подход заключается в следующем:

  • Разбирайте HTML с помощью собственного анализатора HTML
  • Игнорируйте строки, которые находятся в тегах <script> .

Вы не хотите анализировать HTML с помощью регулярных выражений. Вот объяснение, почему: http://htmlparsing.com/regexes.html

В конечном итоге это огорчит вас. Пожалуйста, взгляните на остальные http://htmlparsing.com/ для некоторых указателей, которые могут помочь вам начать.

Вы упомянули в комментарии, что было бы приемлемо удалить теги сценария перед выполнением поиска.

 $data = preg_replace('/<\s*script.*?\/script\s*>/iu', '', $data); 

Этот код может помочь в этом.

Джордж, воскресив этот древний вопрос, потому что у него было простое решение, о котором не упоминалось. Эта ситуация прямо из моего домашнего вопроса о моменте, сопоставьте (или замените) шаблон, за исключением ситуаций s1, s2, s3 и т. Д.

Вы хотите изменить следующее регулярное выражение, чтобы исключить что-либо между <script> и </script> :

 (\bSOMETERM|SOMETERM\b)(?!([^<]+)?>) 

Пожалуйста, простите меня за SOMETERM , что вы SOMETERM $term на SOMETERM , это для ясности, потому что $ имеет особое значение в регулярном выражении.

Со всеми отказами относительно соответствия html в regex, чтобы исключить что-либо между <script> и </script> , вы можете просто добавить это в начало своего регулярного выражения:

 <script>.*?</script>(*SKIP)(*F)| 

поэтому регулярное выражение становится:

 <script>.*?</script>(*SKIP)(*F)|(\bSOMETERM|SOMETERM\b)(?!([^<]+)?>) 

Как это работает?

Левая сторона OR (то есть, | ) соответствует полному <script...</script> , а затем сознательно терпит неудачу. Правая сторона соответствует тому, что вы сравнивали раньше, и мы знаем, что это правильный материал, потому что, если бы это было между тегами скрипта, это бы провалилось.

Справка

Как сопоставить (или заменить) шаблон, за исключением ситуаций s1, s2, s3 …