Grabbing Edits from two strings

后端 未结 4 1660
死守一世寂寞
死守一世寂寞 2021-01-18 08:48

I\'m going to go a bit in-depth with my problem, you can jump to the TL;DR if you don\'t want to read all of this

What I\'m trying to do

I

4条回答
  •  暖寄归人
    2021-01-18 08:59

    Running a proper diff using just JavaScript can be potentially slow, but it depends on the performance requirements and the quality of the diff, and of course how often it must be run.

    One quite efficient way would be to track the edits when the user is actually editing the document and only store those changes just after the moment they are done. For this you can use for example ACE editor, or any other editor that supports change tracking.

    http://ace.c9.io/

    ACE is tracking the changes while the document is edited. The ACE editor tracks the commands in easily comprehensible format like:

    {"action":"insertText","range":{"start":{"row":0,"column":0},
        "end":{"row":0,"column":1}},"text":"d"}
    

    You can hook to the changes of the ACE editor and listen to the change events:

    var changeList = []; // list of changes
    // editor is here the ACE editor instance for example
    var editor = ace.edit(document.getElementById("editorDivId"));
    editor.setValue("original text contents");
    editor.on("change", function(e) {
        // e.data has the change
        var cmd = e.data;
        var range = cmd.range;
        if(cmd.action=="insertText") {
            changeList.push([
                1, 
                range.start.row,
                range.start.column,
                range.end.row,
                range.end.column,
                cmd.text
            ])
        }
        if(cmd.action=="removeText") {
            changeList.push([
                    2, 
                    range.start.row,
                    range.start.column,
                    range.end.row,
                    range.end.column,
                    cmd.text
                ])
        }
        if(cmd.action=="insertLines") {
            changeList.push([
                    3, 
                    range.start.row,
                    range.start.column,
                    range.end.row,
                    range.end.column,
                    cmd.lines
                ])
        }
        if(cmd.action=="removeLines") {
            changeList.push([
                    4, 
                    range.start.row,
                    range.start.column,
                    range.end.row,
                    range.end.column,
                    cmd.lines,
                    cmd.nl
                ])
        }
    });
    

    To learn how it works just create some test runs which capture the changes. Basicly there are only those for commands:

    1. insertText
    2. removeText
    3. insertLines
    4. removeLines

    Removing the newline from the text can be a bit tricky.

    When you have this list of changes you are ready to replay the changes against the text file. You can even merge similar or overlapping changes into a single change - for example inserts to subsequent characters could be merged into a single change.

    There will be some problems when you are testing this, composing the string back to text is not trivial but quite doable and should not be more than around 100 lines of code or so.

    The nice thing is that when you are finished, you have also undo and redo commands easily available, so you can replay the whole editing process.

提交回复
热议问题