util::word_diff (public)

 util::word_diff -old old -new new [ -split_by split_by ] \
    [ -filter_proc filter_proc ] [ -start_old start_old ] \
    [ -end_old end_old ] [ -start_new start_new ] [ -end_new end_new ]

Defined in packages/acs-tcl/tcl/utilities-procs.tcl

Does a word (or character) diff on two lines of text and indicates text that has been deleted/changed or added by enclosing it in start/end_old/new.

Switches:
-old
(required)
The original text.
-new
(required)
The modified text.
-split_by
(optional)
If split_by is a space, the diff will be made on a word-by-word basis. If it is the empty string, it will be made on a char-by-char basis.
-filter_proc
(defaults to "ns_quotehtml") (optional)
A filter to run the old/new text through before doing the diff and inserting the HTML fragments below. Keep in mind that if the input text is HTML, and the start_old, etc... fragments are inserted at arbitrary locations depending on where the diffs are, you might end up with invalid HTML unless the original HTML is quoted.
-start_old
(defaults to "<strike><i><font color="blue">") (optional)
HTML fragment to place before text that has been removed.
-end_old
(defaults to "</font></i></strike>") (optional)
HTML fragment to place after text that has been removed.
-start_new
(defaults to "<u><b><font color="red">") (optional)
HTML fragment to place before new text.
-end_new
(defaults to "</font></b></u>") (optional)
HTML fragment to place after new text.
Author:
Gabriel Burca
See Also:
  • ns_quotehtml

Partial Call Graph (max 5 caller/called nodes):
%3 test_word_diff word_diff (test acs-tcl) util::word_diff util::word_diff test_word_diff->util::word_diff ad_tmpdir ad_tmpdir (public) util::word_diff->ad_tmpdir

Testcases:
word_diff
Source code:

    if {$filter_proc ne ""} {
        set old [$filter_proc $old]
        set new [$filter_proc $new]
    }

    set old_fd [file tempfile old_f [ad_tmpdir]/nsdiff-XXXXXX]
    set new_fd [file tempfile new_f [ad_tmpdir]/nsdiff-XXXXXX]
    puts $old_fd [join [split $old $split_by"\n"]
    puts $new_fd [join [split $new $split_by"\n"]
    close $old_fd
    close $new_fd

    #
    # Diff output is 1 based, our lists are 0 based, so insert a dummy
    # element to start the list with.
    #
    set old_w [linsert [split $old $split_by] 0 {}]
    set sv 1

    try {
        exec -ignorestderr diff -f $old_f $new_f
    } on error {output} {
    } on ok {output} {
    }
    set lines [split $output \n]
    set pos -1
    set nrLines [llength $lines]
    while {1} {
        if {$nrLines < $pos} {
            break
        }
        set diff [lindex $lines [incr pos]]
        if {[regexp {^d(\d+)(\s+(\d+))?$} $diff full m1 m2]} {
            if {$m2 ne ""} {set d_end $m2} else {set d_end $m1}
            for {set i $sv} {$i < $m1} {incr i} {
                append res "${split_by}[lindex $old_w $i]"
            }
            for {set i $m1} {$i <= $d_end} {incr i} {
                append res "${split_by}${start_old}[lindex $old_w $i]${end_old}"
            }
            set sv [expr {$d_end + 1}]
        } elseif {[regexp {^c(\d+)(\s+(\d+))?$} $diff full m1 m2]} {
            if {$m2 ne ""} {set d_end $m2} else {set d_end $m1}
            for {set i $sv} {$i < $m1} {incr i} {
                append res "${split_by}[lindex $old_w $i]"
            }
            for {set i $m1} {$i <= $d_end} {incr i} {
                append res "${split_by}${start_old}[lindex $old_w $i]${end_old}"
            }
            while {1} {
                if {$nrLines < $pos} {
                    break
                }
                set diff [lindex $lines [incr pos]]
                if {$diff eq "."} {
                    break
                } else {
                    append res "${split_by}${start_new}${diff}${end_new}"
                }
            }
            set sv [expr {$d_end + 1}]
        } elseif {[regexp {^a(\d+)$} $diff full m1]} {
            set d_end $m1
            for {set i $sv} {$i <= $m1} {incr i} {
                append res "${split_by}[lindex $old_w $i]"
            }
            while {1} {
                if {$nrLines < $pos} {
                    break
                }
                set diff [lindex $lines [incr pos]]
                if {$diff eq "."} {
                    break
                } else {
                    append res "${split_by}${start_new}${diff}${end_new}"
                }
            }
            set sv [expr {$d_end + 1}]
        }
    }

    for {set i $sv} {$i < [llength $old_w]} {incr i} {
        append res "${split_by}[lindex $old_w $i]"
    }

    file delete -- $old_f $new_f

    return $res
XQL Not present:
PostgreSQL, Oracle
Generic XQL file:
packages/acs-tcl/tcl/utilities-procs.xql

[ hide source ] | [ make this the default ]
Show another procedure: