Поиск и замена слов в HTML
то, что я пытаюсь сделать, это сделать "жаргон".
В основном у меня есть некоторые html и некоторые термины глоссария в базе данных.
Когда человек нажимает на jargon buster, он заменяет слова в тексте хорошей подсказкой (wztooltip), которая показывает им значения.
Я очень старался в этом вопросе и сильно искал этот вопрос
Regex/DOMDocument - сопоставление и замена текста не в ссылке
и кажется, что ответ лежит в файлах simple_html_dom, но у меня возникают проблемы с его работой.
Очевидно, что любые слова, уже связанные, не затрагиваются.
Вот фрагмент того, что у меня есть.
$html = str_get_html($article['content']);
$query_glossary = "SELECT word,glossary_term_id,info FROM glossary_terms WHERE status = 1 ORDER BY LENGTH(word) DESC";
$result_glossary = mysql_query_run($query_glossary);
while($glossary = mysql_fetch_array($result_glossary)) {
$glossary_link = SITEURL.'/glossary/term/'.string_to_url($glossary['word']).'-'.$glossary['glossary_term_id'];
if(strlen($glossary['info'])>400) {
$glossary_info = substr(strip_tags($glossary['info']),0,350).' ...<br /> <a href="'.$glossary_link.'">Read More</a>';
}
else {
$glossary_info = $glossary['info'];
}
$glossary_tip = 'href="javascript:;" onmouseout="UnTip();" class="article_jargon_highligher" onmouseover="'.tooltip_javascript('<a href="'.$glossary_link.'">'.$glossary['word'].'</a>',$glossary_info,400,1,0,1).'"';
$glossary_word = $glossary['word'];
$glossary_word = preg_quote($glossary_word,'/');
//once done we can replace the words with a nice tip
foreach ($html->find('text') as $element) {
if (!in_array($element->parent()->tag,array())) {
//problems are case aren't taken into account and grammer
$element->innertext = str_ireplace(''.$glossary['word'].' ',' <a '.$glossary_tip.' >'.$glossary['word'].'</a> ', $element->innertext);
//$element->innertext = str_ireplace(''.$glossary['word'].',',' <a '.$glossary_tip.'>'.$glossary['word'].'</a> ', $element->innertext);
//$element->innertext = preg_replace ("/\s(".$glossary_word.")\s/ise","nothing(' <a'.'$glossary_tip.'>'.'$1'.'</a> ')" , $element->innertext);
// $element->innertext = str_replace('__glossary_tip_replace__',$glossary_tip, $element->innertext);
}
}
}
$article['content'] = $html->save();
Ответы
Ответ 1
Используйте символ инвертированного слова \W
, чтобы выбрать любые символы, кроме цифр и букв, в вашем шаблоне регулярного выражения. Поскольку это все равно будет терпеть неудачу на границах текстового блока, вам также необходимо будет проверить эти условия. Таким образом, используя слово "термин" в качестве текста, который вы ищете:
(^term$)|(^term\W)|(\Wterm\W)|(\Wterm$)
Первое условие проверяет, чтобы этот термин не был единственным содержимым blob, второй проверяет, имеет ли его первое слово, третье, если оно содержится внутри blob, и последнее, если оно имеет последнее слово.
Если вы хотите рассматривать любые другие символы как символы слов (например, дефис), вам нужно будет отменить \W
с помощью [^\w\-]
.
Надеюсь, это поможет. Возможно, есть оптимизация, которая может быть выполнена, но это должно быть, по крайней мере, хорошей отправной точкой.
Ответ 2
Предполагая, что все слова "слова" вашего глоссария состоят из стандартных "словесных" символов (т.е. [A-Za-z0-9_]
), тогда простое утверждение о границе слова может быть помещено до и после слова в шаблоне регулярных выражений. Попробуйте заменить это утверждение следующим образом:
$element->innertext = preg_replace(
'/\b'. $glossary_word .'\b/i',
'<a '. $glossary_tip .' >'. $glossary['word'] .'</a>',
$element->innertext);
Это предполагает, что $glossary_word
был запущен через preg_quote
(что делает ваш код).
Однако, если слова глоссария могут содержать другие нестандартные словарные символы (например, тире '-'
), может быть сформулировано более сложное регулярное выражение, которое включает в себя lookahead и lookbehind, чтобы гарантировать соответствие только целых слов. Например:
$re_pattern = "/ # Match a glossary whole word.
(?<=[\s'\"]|^) # Word preceded by whitespace, quote or BOS.
{$glossary_word} # Word to be matched.
(?=[\s'\".?!,;:]|$) # Word followed by ws, quote, punct or EOS.
/ix";
Ответ 3
У меня была эта проблема в JS, получающем отдельные слова. Я сделал следующее (вы можете перевести его с JS на PHP):
Он действительно работает ДЕЙСТВИТЕЛЬНО хорошо для меня.:)
var words = document.body.innerHTML;
// FIRST PASS
// remove scripts
words = words.replace(/<script[\s\S]*?>[\s\S]*?<\/script>/gi, '');
// remove CSS
words = words.replace(/<style[\s\S]*?>[\s\S]*?<\/style>/gi, '');
// remove comments
words = words.replace(/<!--[\s\S]*?-->/g, '');
// remove html character entities
words = words.replace(/&.*?;/g, ' ');
// remove all HTML
words = words.replace(/<[\s\S]*?>/g, '');
// SECOND PASS
// remove all newlines
words = words.replace(/\n/g, ' ');
// replace multiple spaces with 1 space
words = words.replace(/\s{2,}/g, ' ');
// split each word
words = words.split(/[^a-z-']+/gi);