Поиск и замена слов в HTML - PullRequest
22 голосов
/ 29 июня 2011

то, что я пытаюсь сделать, это сделать «убийцу жаргона». В основном у меня есть некоторые HTML и некоторые глоссарий терминов в базе данных. Когда человек нажимает на «жаргон», он заменяет слова в тексте хорошей подсказкой (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();

Ответы [ 3 ]

11 голосов
/ 01 июля 2011

Используйте символ перевернутого слова \W, чтобы выбрать любые символы, кроме цифр и букв в шаблоне регулярных выражений. Так как это все равно не получится на границах текстового объекта, вам также необходимо проверить эти условия. Таким образом, используя слово «термин» в качестве текста, который вы ищете:

(^term$)|(^term\W)|(\Wterm\W)|(\Wterm$)

Первое условие проверяет, чтобы убедиться, что термин не является единственным содержимым большого двоичного объекта, второе проверяет, является ли его первым словом, третье - содержится ли оно в большом двоичном объекте, а последнее - последним. 1005 *

Если вы хотите рассматривать любые другие символы как символы слова (например, дефис), вам необходимо заменить \W на [^\w\-].

Надеюсь, это поможет. Вероятно, есть и оптимизации, которые можно выполнить, но это должно быть, по крайней мере, хорошей отправной точкой.

8 голосов
/ 02 июля 2011

Предполагая, что все ваши "слова" в глоссарии состоят из стандартных символов "слова" (т.е. [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 (что делает ваш код).

Однако, если слова глоссария могут содержать другие нестандартные символы слова (например, '-' тире), можно сформулировать более сложное регулярное выражение, которое включает в себя заглядывание вперед и заглядывание назад, чтобы обеспечить совпадение только целых слов. Например:

$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 голосов
/ 07 июля 2011

У меня была эта проблема в 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);
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...