Documentation
¶
Overview ¶
Package diff implement text comparison.
Index ¶
Examples ¶
Constants ¶
const ( // LevelLines captures the differences on lines level. // This will fills the [Data.Adds] and [Data.Dels] only. LevelLines = iota // LevelChunks captures the differences on character level, when // changes is on the same line. // This will fills the [Data.LineChunks], [Data.Adds], and // [Data.Dels]. LevelChunks )
List of comparison levels.
const ( LineKindAdd = '+' LineKindDel = '-' LineKindLabel = '@' LineKindNone = 0 )
List of kind of line in Data.
const DefMatchLen = 5
DefMatchLen minimum number of bytes used for searching the next matched chunk in line.
const DefMatchRatio = 0.7
DefMatchRatio define default minimum match ratio to be considered as change.
Variables ¶
This section is empty.
Functions ¶
func Bytes ¶
Bytes returns the character differences (additions and deletion) between old and new bytes, start at specific position.
Example ¶
fmt.Println(`Additions 1:`)
adds, dels := Bytes([]byte(`00000`), []byte(`00000111`), 0, 0)
fmt.Printf(" adds: %+v\n", adds)
fmt.Printf(" dels: %+v\n", dels)
fmt.Println(`Additions 2:`)
adds, dels = Bytes([]byte(`000000`), []byte(`0001000`), 0, 0)
fmt.Printf(" adds: %+v\n", adds)
fmt.Printf(" dels: %+v\n", dels)
fmt.Println(`Deletions 1:`)
adds, dels = Bytes([]byte(`00000111`), []byte(`00000`), 0, 0)
fmt.Printf(" adds: %+v\n", adds)
fmt.Printf(" dels: %+v\n", dels)
fmt.Println(`Deletions 2:`)
adds, dels = Bytes([]byte(`0001000`), []byte(`000000`), 0, 0)
fmt.Printf(" adds: %+v\n", adds)
fmt.Printf(" dels: %+v\n", dels)
fmt.Println(`Both changes 1:`)
adds, dels = Bytes([]byte(`11000`), []byte(`22000`), 0, 0)
fmt.Printf(" adds: %+v\n", adds)
fmt.Printf(" dels: %+v\n", dels)
fmt.Println(`Both changes 2:`)
adds, dels = Bytes([]byte(`0001000`), []byte(`0002000`), 0, 0)
fmt.Printf(" adds: %+v\n", adds)
fmt.Printf(" dels: %+v\n", dels)
Output: Additions 1: adds: [{StartAt:5,V:111}] dels: [] Additions 2: adds: [{StartAt:3,V:1}] dels: [] Deletions 1: adds: [] dels: [{StartAt:5,V:111}] Deletions 2: adds: [] dels: [{StartAt:3,V:1}] Both changes 1: adds: [{StartAt:0,V:22}] dels: [{StartAt:0,V:11}] Both changes 2: adds: [{StartAt:3,V:2}] dels: [{StartAt:3,V:1}]
func BytesRatio ¶
BytesRatio returns the ratio of matching bytes between old and new. The ratio in in range of 0.0 to 1.0, where 1.0 when both are similar, and 0.0 when no single character matchs found. The minTokenLen define the minimum length of token for searching in both of slice.
It also return the number of characters match-ed and maximum length between old and new. The ratio is computed from match/maxlen.
Example ¶
ratio, m, maxlen := BytesRatio([]byte(`00000`), []byte(`00000111`), 1)
fmt.Printf("Additions 1: %f %d %d\n", ratio, m, maxlen)
ratio, m, maxlen = BytesRatio([]byte(`000000`), []byte(`0001000`), 1)
fmt.Printf("Additions 2: %f %d %d\n", ratio, m, maxlen)
ratio, m, maxlen = BytesRatio([]byte(`00000111`), []byte(`00000`), 1)
fmt.Printf("Deletions 1: %f %d %d\n", ratio, m, maxlen)
ratio, m, maxlen = BytesRatio([]byte(`0001000`), []byte(`000000`), 1)
fmt.Printf("Deletions 2: %f %d %d\n", ratio, m, maxlen)
ratio, m, maxlen = BytesRatio([]byte(`11000`), []byte(`22000`), 1)
fmt.Printf("Both changes 1: %f %d %d\n", ratio, m, maxlen)
ratio, m, maxlen = BytesRatio([]byte(`0001000`), []byte(`0002000`), 1)
fmt.Printf("Both changes 2: %f %d %d\n", ratio, m, maxlen)
Output: Additions 1: 0.625000 5 8 Additions 2: 0.857143 6 7 Deletions 1: 0.625000 5 8 Deletions 2: 0.857143 6 7 Both changes 1: 0.600000 3 5 Both changes 2: 0.857143 6 7
func WriteLines ¶
WriteLines writes each line in lines into w using the Line.String return value.
Types ¶
type Data ¶
type Data struct {
// OldName and NewName stores the file names being compared from
// calling the [Files].
OldName string
NewName string
Adds []Line
Dels []Line
LineChunks []LineChunk
// Unified contains the result of [Unified] diff, without the label
// ("@@ ... @@") and context lines.
// To print the result of unified diff with context lines use
// [Data.WriteUnified].
Unified []Line
IsMatched bool
// contains filtered or unexported fields
}
Data stores additions, deletions, and changes between two texts.
func Files ¶
Files returns the differences between oldfile and newfile.
Example ¶
package main
import (
"fmt"
"log"
"kilabit.info/pakakeh.go/lib/text/diff"
)
func main() {
diff, err := diff.Files(`testdata/lao.txt`, `testdata/tzu.txt`, diff.LevelLines)
if err != nil {
log.Fatal(err)
}
fmt.Println(diff.String())
}
Output: --- testdata/lao.txt +++ testdata/tzu.txt ---- 1/ 1: -"The Way that can be told of is not the eternal Way;" 2/ 2: -"The name that can be named is not the eternal name." 2/ 4: -"The Named is the mother of all things." ++++ 4/ 2: +"The named is the mother of all things." 3/ 3: +"" 11/ 11: +"They both may be called deep and profound." 12/ 12: +"Deeper and more profound," 13/ 13: +"The door of all subtleties!"
func Lines ¶
Lines returns the difference between old and new lines.
Example ¶
package main
import (
"fmt"
"kilabit.info/pakakeh.go/lib/text/diff"
)
func main() {
lao := `The Way that can be told of is not the eternal Way;
The name that can be named is not the eternal name.
The Nameless is the origin of Heaven and Earth;
The Named is the mother of all things.
Therefore let there always be non-being,
so we may see their subtlety,
And let there always be being,
so we may see their outcome.
The two are the same,
But after they are produced,
they have different names.`
tzu := `The Nameless is the origin of Heaven and Earth;
The named is the mother of all things.
Therefore let there always be non-being,
so we may see their subtlety,
And let there always be being,
so we may see their outcome.
The two are the same,
But after they are produced,
they have different names.
They both may be called deep and profound.
Deeper and more profound,
The door of all subtleties!
`
oldlines := diff.ParseLines([]byte(lao))
newlines := diff.ParseLines([]byte(tzu))
diff := diff.Lines(oldlines, newlines, diff.LevelLines)
fmt.Println(diff.String())
}
Output: --- oldlines +++ newlines ---- 1/ 1: -"The Way that can be told of is not the eternal Way;" 2/ 2: -"The name that can be named is not the eternal name." 2/ 4: -"The Named is the mother of all things." ++++ 4/ 2: +"The named is the mother of all things." 3/ 3: +"" 11/ 11: +"They both may be called deep and profound." 12/ 12: +"Deeper and more profound," 13/ 13: +"The door of all subtleties!"
func Text ¶
Text returns the difference between old and new text.
Example ¶
package main
import (
"fmt"
"kilabit.info/pakakeh.go/lib/text/diff"
)
func main() {
lao := `The Way that can be told of is not the eternal Way;
The name that can be named is not the eternal name.
The Nameless is the origin of Heaven and Earth;
The Named is the mother of all things.
Therefore let there always be non-being,
so we may see their subtlety,
And let there always be being,
so we may see their outcome.
The two are the same,
But after they are produced,
they have different names.`
tzu := `The Nameless is the origin of Heaven and Earth;
The named is the mother of all things.
Therefore let there always be non-being,
so we may see their subtlety,
And let there always be being,
so we may see their outcome.
The two are the same,
But after they are produced,
they have different names.
They both may be called deep and profound.
Deeper and more profound,
The door of all subtleties!
`
diff := diff.Text([]byte(lao), []byte(tzu), diff.LevelLines)
fmt.Println(diff.String())
}
Output: --- old +++ new ---- 1/ 1: -"The Way that can be told of is not the eternal Way;" 2/ 2: -"The name that can be named is not the eternal name." 2/ 4: -"The Named is the mother of all things." ++++ 4/ 2: +"The named is the mother of all things." 3/ 3: +"" 11/ 11: +"They both may be called deep and profound." 12/ 12: +"Deeper and more profound," 13/ 13: +"The door of all subtleties!"
func Unified ¶
Unified returns the unified changes between old and new bytes.
References,
- https://www.gnu.org/software/diffutils/manual/html_node/Unified-Format.html
- https://www.gnu.org/software/diffutils/manual/html_node/Hunks.html
Example ¶
package main
import (
"fmt"
"strings"
"kilabit.info/pakakeh.go/lib/text/diff"
)
func main() {
lao := `The Way that can be told of is not the eternal Way;
The name that can be named is not the eternal name.
The Nameless is the origin of Heaven and Earth;
The Named is the mother of all things.
Therefore let there always be non-being,
so we may see their subtlety,
And let there always be being,
so we may see their outcome.
The two are the same,
But after they are produced,
they have different names.`
tzu := `The Nameless is the origin of Heaven and Earth;
The named is the mother of all things.
Therefore let there always be non-being,
so we may see their subtlety,
And let there always be being,
so we may see their outcome.
The two are the same,
But after they are produced,
they have different names.
They both may be called deep and profound.
Deeper and more profound,
The door of all subtleties!
`
dif := diff.Unified([]byte(lao), []byte(tzu))
var sb strings.Builder
dif.WriteUnified(&sb, 3)
fmt.Println(sb.String())
}
Output: --- old +++ new @@ -1,7 +1,6 @@ -The Way that can be told of is not the eternal Way; -The name that can be named is not the eternal name. The Nameless is the origin of Heaven and Earth; -The Named is the mother of all things. +The named is the mother of all things. + Therefore let there always be non-being, so we may see their subtlety, And let there always be being, @@ -9,3 +8,6 @@ The two are the same, But after they are produced, they have different names. +They both may be called deep and profound. +Deeper and more profound, +The door of all subtleties!
func (*Data) PushChange ¶
PushChange adds the old and new line to Dels, Adds, and Data.LineChunks respectively.
func (*Data) PushDel ¶
PushDel adds deletion line to slice of Dels.
func (Data) String ¶
String returns the additions and deletions with custom format. The custom format as follow,
--- <OldName> +++ <NewName> ---- <NumOther>/ <Num>: <Kind><QuotedVal> ++++ <NumOther>/ <Num>: <Kind><Val>
The lines after "----" is the deleted lines from the old text. The lines after "++++" is the added lines from the new text.
The NumOther is the line number from the other text. The Num is the line number where line is deleted in old text, or added in new text.
The Kind is '-' for deletion or '+' for addition.
The QuotedVal value is the line text printed inside double quotes.
func (Data) WriteLineChunks ¶
WriteLineChunks writes the formatted line changes and chunks differences into w. The format of output is,
--- <OldName> +++ <NewName> --++ <LineChunk> ...
The OldName and NewName is the file name being compared. See the LineChunk.String for the format of each LineChunk.
type Line ¶
type Line struct {
Val []byte // The line value.
Kind int // The kind of changes.
Num int // The line number, started from 1.
NumOther int // The line number of other file.
}
Line represents single line from file or stream of bytes.
func ParseLines ¶
ParseLines returns lines from reading raw bytes. The line number returned in lines started from 1.
func ReadLines ¶
ReadLines returns lines in the file. The line number returned in lines started from 1.
func (Line) String ¶
Strings returns the formatted line data. The format is as follow,
<NumOther>/<Num>: <Kind><QuotedVal>
The NumOther is line number from other text being compared. The Num is line number. The Kind is '-' for deletion or '+' for addition. The QuotedVal is double quoted line text, to help human compare and see the changes for non-printable characters.
type LineChunk ¶
LineChunk represents a changes inside a line. Each chunk in Adds and Dels contains the position and value of string that is added in New or deleted in Old line.
func (LineChunk) String ¶
String returns formatted content of LineChunk. The format is as follow,
<OldLine> <NewLine> ^<StartAt> <Kind> <QuotedVal>
The OldLine and NewLine print the line being compared, using the format from Line.String. The StartAt print the beginning position where changes found between old and new line. The Kind print '-' for deletion or '+' for deletion. The QuoteVal print the string difference in double quote.
Source Files
¶
- diff.go
- func.go
- line.go
- line_chunk.go
- unified.go