【问题标题】:How to highlight the difference of two texts with css? [closed]如何用css突出两个文本的区别? [关闭]
【发布时间】:2016-06-26 09:44:02
【问题描述】:

我知道如何使用 this script 使用 CSS 突出显示部分文本:

span.highlight {
    background-color: #B4D5FF;
}

现在我想强调两个字符串的区别。例如给定以下两个字符串:

这是123号

那是124号

我需要像我在此处显示的那样突出显示文本。有人可以帮我实现吗?

span.highlight {background-color: #B4D5FF}
<p>this is number 123</p>
<p>
th<span class="highlight">at</span> is number 12<span class="highlight">4</span>
</p>

【问题讨论】:

  • 我建议在网上搜索一个现有的图书馆,因为这不是一个 1 答案的问题......这是一项相当大的工作
  • that is number 124 是静态文本或来自其他地方,我的意思是来自databasejavascript
  • 要突出显示字符串的哪一部分?
  • @FastSnail 有时会起作用。
  • @M.Tanzil 你什么意思?对解决方案有影响吗?

标签: javascript jquery html css


【解决方案1】:

您需要使用split() 方法获取新字符串的所有字符并迭代每个字符并与旧字符串的字符进行比较。

highlight($("#new"), $("#old"));

function highlight(newElem, oldElem){ 
  var oldText = oldElem.text(),     
      text = '';
  newElem.text().split('').forEach(function(val, i){
    if (val != oldText.charAt(i))
      text += "<span class='highlight'>"+val+"</span>";  
    else
      text += val;            
  });
  newElem.html(text); 
}
.highlight {background-color: #B4D5FF}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<p id="old">this is number 123</p>
<p id="new">that is number 124</p>

您也可以使用更简单的代码,如下所示

highlight($("#new"), $("#old"));

function highlight(newElem, oldElem){ 
  newElem.html(newElem.text().split('').map(function(val, i){
    return val != oldElem.text().charAt(i) ?
      "<span class='highlight'>"+val+"</span>" : 
      val;            
  }).join('')); 
}
.highlight {background-color: #B4D5FF}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<p id="old">this is number 123</p>
<p id="new">that is number 124</p>

如果你想使用更少的跨度检查底部代码

highlight($("#new"), $("#old"));

function highlight(newElem, oldElem){ 
  var oldText = oldElem.text(),     
      text = '',
      spanOpen = false;  
  newElem.text().split('').forEach(function(val, i){  
    if (val != oldText.charAt(i)){   
      text += !spanOpen ? "<span class='highlight'>" : "";
      spanOpen = true;
    } else {       
      text += spanOpen ? "</span>" : "";
      spanOpen = false;  
    }  
    text += val;
  });
  newElem.html(text); 
}
.highlight {background-color: #B4D5FF}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<p id="old">this is number 123</p>
<p id="new">that is number 124</p>

【讨论】:

  • 我喜欢你的回答多么简洁!我想用我的解决方案你会有更少的 标签,因为我会寻找范围而不是为每个字符添加一个 标签,但我喜欢它的优雅!
  • @OmarShehata 查看跨度较小的新示例。
  • 感谢您提供代码 sn-p。就像我评论奥马尔的回答一样,如果我将“123”更改为“12”,则不会突出显示任何内容,而我认为应该在此处突出显示某些内容以反映更改。看来我必须使用 diff 库,正如每个人都推荐的那样:)
  • @Meysam 最好的方法是使用 libray,但我回答了你的问题和你的例子。
  • 好吧,我把你的回答标记为接受了 :)
【解决方案2】:

因此您必须使用 Javascript 来完成此操作,因为它涉及到相当多的逻辑。正如其他答案中提到的,检测文本中的差异比逐个字符地检查要复杂一些。

但是,出于好奇,我将这个简单的实现放在一起:

CodePen

获得差异的函数如下所示:

function getDiff(text1,text2){
  //Takes in two strings 
  //Returns an array of the span of the differences 
  //So if given:
  // text1: "that is number 124"
  // text2: "this is number 123"
  //It will return:
  // [[2,4],[17,18]]
  //If the strings are of different lengths, it will check up to the end of text1 
  //If you want it to do case-insensitive difference, just convert the texts to lowercase before passing them in 
  var diffRange = []
  var currentRange = undefined
  for(var i=0;i<text1.length;i++){
    if(text1[i] != text2[i]){
      //Found a diff! 
      if(currentRange == undefined){
        //Start a new range 
        currentRange = [i]
      }
    }
    if(currentRange != undefined && text1[i] == text2[i]){
      //End of range! 
      currentRange.push(i)
      diffRange.push(currentRange)
      currentRange = undefined
    }
  }
  //Push any last range if there's still one at the end 
  if(currentRange != undefined){
    currentRange.push(i)
    diffRange.push(currentRange)
  }
  return diffRange;
}

函数getDiff 接收两个字符串,并返回它们不同的范围。只要两个字符串的长度相同,这就会很好。

所以要使用它,我要做的就是:

var text1 = "that is number 124"
var text2 = "this is number 123"
var diffRange = getDiff(text1,text2)

尝试更改 CodePen 中的文本并观察它的更新!

一旦获得这些范围,它就会生成 html 并插入 &lt;span&gt; 标签,并将元素添加到页面中。如果你知道你的字符串总是一样的,这就足够了。否则,最好查看 Javascript 差异库! (Jsdiff 似乎是一个不错的库)

【讨论】:

  • 感谢您提供的代码示例。您的示例的一件事是,如果我将“123”更改为“12”,则不会突出显示任何内容,而我认为应该在此处突出显示某些内容以反映更改:)
  • 就像我说的,这只有在字符串长度相同时才有效。这就是为什么其他人都建议您使用差异库来处理这样的删除:)
  • 你说得对,非常感谢
【解决方案3】:

'Diffing' 文本比乍看起来更复杂。这取决于您希望如何检测每个差异,但总的来说,您希望检测:

  • 角色级别的变化(123 与 124)
  • 添加文字(“我去过悉尼”与“我从未去过悉尼”)。
  • 删除文本(与前面的示例相反)。

棘手的一点是检测两个字符串之间的差异和共同点。一个简单的实现可能只是逐个字符地比较字符串。这样做的问题是,只要添加或删除一个字符,字符串的其余部分就会出现差异,即使它实际上与原始文本相同。

最好的办法是使用现有的差异库。 Javascript有很多。这个:https://github.com/kpdecker/jsdiff 看起来不错,尽管对于您需要的东西可能有点矫枉过正。不过基本上 - 不要试图自己发明这个,除非你想学习很多关于文本解析的知识!

【讨论】:

    【解决方案4】:

    当然前面的答案是正确的,但是如果你有一个非常具体的格式来比较并且不想使用外部框架,那么可以使用像这样的 javascript 来对你的字符进行分组并使用 css 设置它们的样式:

    <html>
    
    <style type="text/css">
    .highlighted{
        background-color:blue;
    }
    </style>
    
    <script type="text/javascript">
    
    function init(){
        var output = document.getElementById("output");
        output.appendChild(highlightChanges("12777345aaaabbbbb","1277845abaababababababadsrfgadsg"));
    }
    
    var highlightChanges = function(str, compareStr){
        var strlength = str.length > compareStr.length ? compareStr.length : str.length;
        var allStr = document.createElement("span");
        var hl = null;
        var nohl = null;
        for(i = 0; i < strlength ; i++){
            if(str.charAt(i) != compareStr.charAt(i)){
                if(nohl != null){ 
                    allStr.appendChild(nohl);
                    nohl = null;
                }
                if(hl != null) hl.innerHTML += str.charAt(i);
                else{
                    hl = document.createElement("span");
                    hl.classList.add("highlighted");
                    hl.innerHTML = str.charAt(i);
                } 
            }
            else{
                if(hl != null){
                    allStr.appendChild(hl);
                    hl = null;
                }
                if(nohl != null) nohl.innerHTML += str.charAt(i);
                else{
                    nohl = document.createElement("span");
                    nohl.innerHTML = str.charAt(i);
                } 
            }
    
            <!-- Fix by James Moberg to prevent premature end of comparison-->
            if(hl != null){
                allStr.appendChild(hl);
            } else if (nohl != null){
                allStr.appendChild(nohl);
            }
        }
        return allStr;
    }
    </script>
    
    <body onload="init()">
        <div id="output"></div>
    </body>
    
    </html>
    

    【讨论】:

    • 仅供参考:[4 年后] 您需要在“for”循环的末尾添加一个额外的检查以确定是否 h1!==null 然后 appendChild 或结果可能会被截断太早了,不会返回完整的结果。
    • 更正:如果 h1 或 nohl 不为 null,则 appendChild 变量或不返回完整结果。这是我所做的更改gist.github.com/JamoCA/94d97a3e4250e0810b8b75423a1dbbc3
    猜你喜欢
    • 2010-09-24
    • 2018-04-26
    • 2016-01-17
    • 2018-02-10
    • 2014-10-10
    • 2015-01-08
    • 2017-12-15
    • 2020-09-30
    • 1970-01-01
    相关资源
    最近更新 更多