【问题标题】:Search and Replace Words in HTML在 HTML 中搜索和替换单词
【发布时间】:2011-09-25 02:46:04
【问题描述】:

我想做的是制作一个“行话终结者”。 基本上我在数据库中有一些 html 和一些词汇表术语。 当人们点击 jargon buster 时,它会用一个漂亮的工具提示 (wztooltip) 替换文本中的单词,从而显示它们的含义。

我一直在努力解决这个问题,并认真研究了这个问题 Regex / DOMDocument - match and replace text not in a link

似乎答案就在 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();

【问题讨论】:

  • 我是同事。真正的问题是我们很难让代码只匹配单个单词而不是单词中的单词(即:也许是 APS)。这些词也在 HTML 中。所以这需要考虑。
  • 这肯定只是编写一个足够强大的正则表达式的一个例子,可能使用空格和标点符号来检测单词边界,尽管我不会因为尝试而让自己尴尬。 +1
  • 你想要JS解决方案还是PHP解决方案,因为你使用了两个标签?
  • 嗨,我不久前写了一个维基媒体扩展,它做了类似的事情。根据您的方法,很容易得到一个低效的解决方案。可能对你有帮助:github.com/bcoughlan/Extension-Lingo/blob/master/Lingo.php

标签: php javascript regex dom replace


【解决方案1】:

我在 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);

【讨论】:

    【解决方案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 运行(您的代码就是这样做的)。

    但是,如果词汇表中的单词可能包含其他非标准单词字符(例如 '-' 破折号),则可以制定更复杂的正则表达式,其中包含前瞻和后瞻,以确保仅匹配整个单词。例如:

    $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";
    

    【讨论】:

    • 是的,我遇到的问题是单词与单词格式不匹配
    • @Richard Housham:第二个较长的正则表达式适用于 任何 单词(甚至是包含空格的短语)。
    【解决方案3】:

    使用倒置单词字符\W 选择正则表达式模式中除数字和字母以外的任何字符。因为这仍然会在文本 blob 的边界处失败,所以您还需要测试这些条件。因此,使用单词“term”作为您要搜索的文本:

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

    第一个条件检查以确保 term 不是 blob 的唯一内容,第二个条件检查它是否是第一个单词,第三个条件是否包含在 blob 中,最后一个条件是否是最后一个单词。

    如果您想将任何其他字符视为单词字符(例如连字符),您需要将 \W 替换为 [^\w\-]

    希望这会有所帮助。可能还有一些可以执行的优化,但这至少应该是一个很好的起点。

    【讨论】:

    • 他也可以简单地将^$包含在[]
    • ^ inside [] 表示别的意思。 $ 将映射到美元符号。但是,您可以执行 (^|\W)(term)(\W|$) 之类的操作
    • @Gerben 好多了!但是,再想一想,这个(以及我之前的模式)现在提出了另一个问题:非单词字符也将包含在匹配中。这将需要额外的逻辑来排除它们......
    • 以下答案使用\b,它是一个长度为0(因此它不会添加到您的匹配组中)的特殊符号,表示单词边界(即\w 与@987654330 相遇的地方@,以任意顺序)。您可能会发现这很有用。
    猜你喜欢
    • 2011-09-13
    • 1970-01-01
    • 2016-03-08
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2010-11-05
    • 1970-01-01
    相关资源
    最近更新 更多