JQ 實現對比兩個文本的差異並高亮顯示差異部分

来源:https://www.cnblogs.com/zxf100/archive/2022/07/06/16452557.html
-Advertisement-
Play Games

利用jq對比兩段文本的差異,差異的內容用不同顏色表示出來。 線上參考demo:http://incaseofstairs.com/jsdiff/ 項目地址:https://github.com/kpdecker/jsdiff 先上效果圖: 左側第一列是原稿,第二列是需要對比稿,第三列是對比後的結果。 ...


利用jq對比兩段文本的差異,差異的內容用不同顏色表示出來。

線上參考demo:
http://incaseofstairs.com/jsdiff/

項目地址:
https://github.com/kpdecker/jsdiff

先上效果圖:

 

 左側第一列是原稿,第二列是需要對比稿,第三列是對比後的結果。

紅色文字刪除線表示對比稿相對原稿缺少的文字,綠色下劃線文字表示對比稿相對原稿新增的文字。

同時支持三種方式:Chars,以字元顯示差異;Words,以整句或段顯示對比差異;Lines以行顯示差異。

 

html源碼:

<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8">
    <title>比較文本差異</title>
    <style type="text/css">
        table { width: 100%; height: 600px; }
        tr { flex-direction: row; display: -webkit-flex; display: flex; height: 100%; -webkit-flex-wrap: wrap; flex-wrap: wrap; }
            tr td { width: 33%; border: 1px solid #000000; }
        del { background: #ff0000; }
        ins { background: #00ff21; }
    </style>
</head>
<body>

    <div id="settings">
        <h1>比較文本差異(只適合比較純文本且不帶html標簽)</h1>
        <label><input type="radio" name="diff_type" value="diffChars" checked> Chars</label>
        <label><input type="radio" name="diff_type" value="diffWords"> Words</label>
        <label><input type="radio" name="diff_type" value="diffLines"> Lines</label>
    </div>
    <a href="https://github.com/kpdecker/jsdiff" class="source">github.com/kpdecker/jsdiff</a>
    <table>
        <tr>
            <td contenteditable="true" id="a">restaurant</td>
            <td contenteditable="true" id="b">aura</td>
            <td><div id="result"></div></td>
        </tr>
    </table>

    <script src="/static/index/js/diff.js"></script>
    <script defer>
        var a = document.getElementById('a');
        var b = document.getElementById('b');
        var result = document.getElementById('result');

        function changed() {
            console.log('***********************************************');
            var oldContent = a.textContent;
            var content1 = b.textContent;

            //console.log("content1-----");
            //console.log(content1);

            //diffChars以字元顯示差異
            //diffWords以整句或段顯示對比差異
            //diffLines以行顯示差異
            //window.diffType
            var diff = JsDiff[window.diffType](oldContent, content1);
            var arr = new Array();
            for (var i = 0; i < diff.length; i++) {
                if (diff[i].added && diff[i + 1] && diff[i + 1].removed) {
                    var swap = diff[i];
                    diff[i] = diff[i + 1];
                    diff[i + 1] = swap;
                }
                console.log(diff[i]);
                var diffObj = diff[i];
                var content = diffObj.value;

                //可以考慮啟用,特別是後臺清理HTML標簽後的文本
                if (content.indexOf("\n") >= 0) {
                    //console.log("有換行符");
                    //替換為<br/>
                    var reg = new RegExp('\n', 'g');
                    content = content.replace(reg, '<br/>');
                }

                //var reg2 = new RegExp('##em2', 'g');
                //var reg3 = new RegExp('replace##', 'g');
                //content = content.replace(reg2, '');
                //content = content.replace(reg3, '');

                if (diffObj.removed) {
                    arr.push('<del title="刪除的部分">' + content + '</del>');
                } else if (diffObj.added) {
                    arr.push('<ins title="新增的部分">' + content + '</ins>');
                } else {
                    //沒有改動的部分
                    arr.push('<span title="沒有改動的部分">' + content + '</span>');
                }
            }
            var html = arr.join('');
            //var reg = new RegExp('##em2.replace##', 'g');
            //html = html.replace(reg, '<span style="text-indent:2em;display: inline-block;">&nbsp;</span>');
            //$("#" + newId+"_show").html(html);
            //$("#result").html(html);
            result.innerHTML = html;
        }
        //function changed() {
        //    var diff = JsDiff[window.diffType](a.textContent, b.textContent);
        //    var fragment = document.createDocumentFragment();
        //    for (var i=0; i < diff.length; i++) {
        //        if (diff[i].added && diff[i + 1] && diff[i + 1].removed) {
        //            var swap = diff[i];
        //            diff[i] = diff[i + 1];
        //            diff[i + 1] = swap;
        //        }
        //        var node;
        //        if (diff[i].removed) {
        //            node = document.createElement('del');
        //            node.appendChild(document.createTextNode(diff[i].value));
        //        } else if (diff[i].added) {
        //            node = document.createElement('ins');
        //            node.appendChild(document.createTextNode(diff[i].value));
        //        } else {
        //            node = document.createTextNode(diff[i].value);
        //        }
        //        fragment.appendChild(node);
        //    }
        //    result.textContent = '';
        //    result.appendChild(fragment);
        //}

        window.onload = function () {
            onDiffTypeChange(document.querySelector('#settings [name="diff_type"]:checked'));
            changed();
        };

        a.onpaste = a.onchange =
            b.onpaste = b.onchange = changed;

        if ('oninput' in a) {
            a.oninput = b.oninput = changed;
        } else {
            a.onkeyup = b.onkeyup = changed;
        }

        function onDiffTypeChange(radio) {
            window.diffType = radio.value;
            document.title = "Diff " + radio.value.slice(4);
        }

        var radio = document.getElementsByName('diff_type');
        for (var i = 0; i < radio.length; i++) {
            radio[i].onchange = function (e) {
                onDiffTypeChange(e.target);
                changed();
            }
        }
    </script>
</body>
</html>

 

JQ代碼

/*!

 diff v2.0.1

Software License Agreement (BSD License)

Copyright (c) 2009-2015, Kevin Decker <[email protected]>

All rights reserved.

Redistribution and use of this software in source and binary forms, with or without modification,
are permitted provided that the following conditions are met:

* Redistributions of source code must retain the above
  copyright notice, this list of conditions and the
  following disclaimer.

* Redistributions in binary form must reproduce the above
  copyright notice, this list of conditions and the
  following disclaimer in the documentation and/or other
  materials provided with the distribution.

* Neither the name of Kevin Decker nor the names of its
  contributors may be used to endorse or promote products
  derived from this software without specific prior
  written permission.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR
IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
@license
*/
(function webpackUniversalModuleDefinition(root, factory) {
    if(typeof exports === 'object' && typeof module === 'object')
        module.exports = factory();
    else if(typeof define === 'function' && define.amd)
        define(factory);
    else if(typeof exports === 'object')
        exports["JsDiff"] = factory();
    else
        root["JsDiff"] = factory();
})(this, function() {
return /******/ (function(modules) { // webpackBootstrap
/******/     // The module cache
/******/     var installedModules = {};

/******/     // The require function
/******/     function __webpack_require__(moduleId) {

/******/         // Check if module is in cache
/******/         if(installedModules[moduleId])
/******/             return installedModules[moduleId].exports;

/******/         // Create a new module (and put it into the cache)
/******/         var module = installedModules[moduleId] = {
/******/             exports: {},
/******/             id: moduleId,
/******/             loaded: false
/******/         };

/******/         // Execute the module function
/******/         modules[moduleId].call(module.exports, module, module.exports, __webpack_require__);

/******/         // Flag the module as loaded
/******/         module.loaded = true;

/******/         // Return the exports of the module
/******/         return module.exports;
/******/     }


/******/     // expose the modules object (__webpack_modules__)
/******/     __webpack_require__.m = modules;

/******/     // expose the module cache
/******/     __webpack_require__.c = installedModules;

/******/     // __webpack_public_path__
/******/     __webpack_require__.p = "";

/******/     // Load entry module and return exports
/******/     return __webpack_require__(0);
/******/ })
/************************************************************************/
/******/ ([
/* 0 */
/***/ function(module, exports, __webpack_require__) {

    /* See LICENSE file for terms of use */

    /*
     * Text diff implementation.
     *
     * This library supports the following APIS:
     * JsDiff.diffChars: Character by character diff
     * JsDiff.diffWords: Word (as defined by \b regex) diff which ignores whitespace
     * JsDiff.diffLines: Line based diff
     *
     * JsDiff.diffCss: Diff targeted at CSS content
     *
     * These methods are based on the implementation proposed in
     * "An O(ND) Difference Algorithm and its Variations" (Myers, 1986).
     * http://citeseerx.ist.psu.edu/viewdoc/summary?doi=10.1.1.4.6927
     */
    'use strict';

    exports.__esModule = true;
    // istanbul ignore next

    function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; }

    var _diffBase = __webpack_require__(1);

    var _diffBase2 = _interopRequireDefault(_diffBase);

    var _diffCharacter = __webpack_require__(3);

    var _diffWord = __webpack_require__(4);

    var _diffLine = __webpack_require__(5);

    var _diffSentence = __webpack_require__(6);

    var _diffCss = __webpack_require__(7);

    var _diffJson = __webpack_require__(8);

    var _patchApply = __webpack_require__(9);

    var _patchCreate = __webpack_require__(10);

    var _convertDmp = __webpack_require__(12);

    var _convertXml = __webpack_require__(13);

    exports.Diff = _diffBase2['default'];
    exports.diffChars = _diffCharacter.diffChars;
    exports.diffWords = _diffWord.diffWords;
    exports.diffWordsWithSpace = _diffWord.diffWordsWithSpace;
    exports.diffLines = _diffLine.diffLines;
    exports.diffTrimmedLines = _diffLine.diffTrimmedLines;
    exports.diffSentences = _diffSentence.diffSentences;
    exports.diffCss = _diffCss.diffCss;
    exports.diffJson = _diffJson.diffJson;
    exports.structuredPatch = _patchCreate.structuredPatch;
    exports.createTwoFilesPatch = _patchCreate.createTwoFilesPatch;
    exports.createPatch = _patchCreate.createPatch;
    exports.applyPatch = _patchApply.applyPatch;
    exports.convertChangesToDMP = _convertDmp.convertChangesToDMP;
    exports.convertChangesToXML = _convertXml.convertChangesToXML;
    exports.canonicalize = _diffJson.canonicalize;


/***/ },
/* 1 */
              
您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 近日,中國信通院、雲計算開源產業聯盟正式對外發佈《雲原生產品目錄》,騰訊雲原生資料庫TDSQL-C憑藉其超強性能、極致效率的彈性伸縮和完善的產品化解決方案體系,成功入圍目錄。 全球數字經濟進入高速發展期,在敏捷、高效、降本需求的驅動下,雲原生已經成為提升雲計算使用效能的關鍵支撐,正引領新一代軟體架構 ...
  • 機器規劃 環境準備 安裝JDK 1. 在所有機器上安裝jdk8 2. 配置好環境變數 vi /etc/profile JAVA_HOME=/usr/local/jdk1.8.0_152 PATH=$PATH:$JAVA_HOME/bin export JAVA_HOME export PATH so ...
  • 7月4日,國際權威機構IDC發佈的《2021年下半年中國關係型資料庫軟體市場跟蹤報告》顯示,騰訊雲資料庫在關係型資料庫軟體市場(公有雲模式)中,位列第二。 IDC報告顯示,2021下半年中國關係型資料庫軟體市場規模為15.8億美元,同比增長34.9%。其中,公有雲關係型資料庫規模8.7億美元,同比增 ...
  • #RDD(2) ##RDD轉換運算元 RDD根據數據處理方式的不同將運算元整體上分為Value類型、雙Value類型、Key-Value類型 ###value類型 ####map 函數簽名 def map[U:ClassTag](f:T=>U):RDD[U] 函數說明 將處理的數據逐條進行映射轉換,這裡 ...
  • ZEGO 提供 ZIM + RTC 服務聯動的場景解決方案,公開語聊房、秀場直播等業務場景搭建的示例源碼,幫助開發者能在極短的時間內搭建完美的業務場景。 ...
  • 目前正在做的一個項目需要用到地圖功能,在使用數據線連接到手機進行真機調試的時候,由於uniapp自帶了高德的SDK能夠獲取位置信息,但是在打包成apk後就不行了,原先地圖的位置顯示一片空白,這個時候,就需要我們去高德(或者百度)開放平臺去申請應用的key了,在這裡以高德地圖為例,步驟如下: 第一步: ...
  • 2022年6月,HMS Core機器學習服務面向開發者提供一項全新的開放能力——同聲傳譯,通過AI語音技術減少資源成本,加強溝通交流,旨在幫助開發者製作豐富多樣的同聲傳譯應用。 HMS Core同聲傳譯涵蓋了機器學習服務的語音識別、翻譯、語音合成等核心技術,首先把輸入的實時語音轉換成文字,然後再把文 ...
  • Android系統日誌和工具 我們經常需要查看設備裡面的各種日誌信息。所以有必要瞭解android系統裡面有哪些日誌,以及用什麼方式可以提取這些日誌。以我手頭的紅米note4xplus為例,其基本配置為高通msm8953,android7.0。我們可以看一下根文件系統: mido:/ # ls ac ...
一周排行
    -Advertisement-
    Play Games
  • 示例項目結構 在 Visual Studio 中創建一個 WinForms 應用程式後,項目結構如下所示: MyWinFormsApp/ │ ├───Properties/ │ └───Settings.settings │ ├───bin/ │ ├───Debug/ │ └───Release/ ...
  • [STAThread] 特性用於需要與 COM 組件交互的應用程式,尤其是依賴單線程模型(如 Windows Forms 應用程式)的組件。在 STA 模式下,線程擁有自己的消息迴圈,這對於處理用戶界面和某些 COM 組件是必要的。 [STAThread] static void Main(stri ...
  • 在WinForm中使用全局異常捕獲處理 在WinForm應用程式中,全局異常捕獲是確保程式穩定性的關鍵。通過在Program類的Main方法中設置全局異常處理,可以有效地捕獲並處理未預見的異常,從而避免程式崩潰。 註冊全局異常事件 [STAThread] static void Main() { / ...
  • 前言 給大家推薦一款開源的 Winform 控制項庫,可以幫助我們開發更加美觀、漂亮的 WinForm 界面。 項目介紹 SunnyUI.NET 是一個基於 .NET Framework 4.0+、.NET 6、.NET 7 和 .NET 8 的 WinForm 開源控制項庫,同時也提供了工具類庫、擴展 ...
  • 說明 該文章是屬於OverallAuth2.0系列文章,每周更新一篇該系列文章(從0到1完成系統開發)。 該系統文章,我會儘量說的非常詳細,做到不管新手、老手都能看懂。 說明:OverallAuth2.0 是一個簡單、易懂、功能強大的許可權+可視化流程管理系統。 有興趣的朋友,請關註我吧(*^▽^*) ...
  • 一、下載安裝 1.下載git 必須先下載並安裝git,再TortoiseGit下載安裝 git安裝參考教程:https://blog.csdn.net/mukes/article/details/115693833 2.TortoiseGit下載與安裝 TortoiseGit,Git客戶端,32/6 ...
  • 前言 在項目開發過程中,理解數據結構和演算法如同掌握蓋房子的秘訣。演算法不僅能幫助我們編寫高效、優質的代碼,還能解決項目中遇到的各種難題。 給大家推薦一個支持C#的開源免費、新手友好的數據結構與演算法入門教程:Hello演算法。 項目介紹 《Hello Algo》是一本開源免費、新手友好的數據結構與演算法入門 ...
  • 1.生成單個Proto.bat內容 @rem Copyright 2016, Google Inc. @rem All rights reserved. @rem @rem Redistribution and use in source and binary forms, with or with ...
  • 一:背景 1. 講故事 前段時間有位朋友找到我,說他的窗體程式在客戶這邊出現了卡死,讓我幫忙看下怎麼回事?dump也生成了,既然有dump了那就上 windbg 分析吧。 二:WinDbg 分析 1. 為什麼會卡死 窗體程式的卡死,入口門檻很低,後續往下分析就不一定了,不管怎麼說先用 !clrsta ...
  • 前言 人工智慧時代,人臉識別技術已成為安全驗證、身份識別和用戶交互的關鍵工具。 給大家推薦一款.NET 開源提供了強大的人臉識別 API,工具不僅易於集成,還具備高效處理能力。 本文將介紹一款如何利用這些API,為我們的項目添加智能識別的亮點。 項目介紹 GitHub 上擁有 1.2k 星標的 C# ...