differ

package module
v1.1.2 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Jul 17, 2023 License: Apache-2.0 Imports: 5 Imported by: 0

README

differ

Differ is a Go library for finding the differences between two sequences.

Superceded by my Diff2 package—itself based on this package's code.

License

Apache-2.0


Documentation

Overview

Differ is a package for finding the differences between two sequences.

Differ uses a sequence matcher based on a slightly simplified version of Python's difflib sequence matcher.

Thanks to generics Differ can compare any two slices of comparables. (Although comparing float sequences is not recommended.) And using a key function it can also compare two slices of structs.

See New for how to create a Differ value and NewKeyFn for how to create a DifferKeyFn value which can be used to compare sequences of structs.

Deprecated: Use [Diff2](https://github.com/mark-summerfield/diff2) instead.

Index

Examples

Constants

This section is empty.

Variables

View Source
var Version string

Functions

This section is empty.

Types

type Block

type Block[T comparable] struct {
	Tag   Tag
	Items []T
}

type BlockKeyFn added in v1.1.0

type BlockKeyFn[T any] struct {
	Tag   Tag
	Items []T
}

type Differ

type Differ[T comparable] struct {
	A []T
	B []T
	// contains filtered or unexported fields
}

func New

func New[T comparable](a, b []T) *Differ[T]

New returns a Differ value based on the provided a and b slices. These slices are only ever read and may be accessed as .A and .B. After creating a Differ, call [Blocks] (or [Spans]) to see the differences.

func (*Differ[T]) Blocks

func (me *Differ[T]) Blocks() []Block[T]

Blocks returns a sequence of Block values representing how to go from a to b. Each block has a Tag and a sequence of items. This is the easiest method for seeing the differences in two sequences. See also [Spans].

Example (Common)
a := strings.Fields("foo\nbar\nbaz\nquux")
b := strings.Fields("foo\nbaz\nbar\nquux")
differ := New(a, b)
blocks := differ.Blocks()
for _, block := range blocks {
	fmt.Println(block.Tag, strings.Join(block.Items, " "))
}
Output:

= foo
+ baz
= bar
- baz
= quux
Example (Ints)
a := []int{1, 2, 3, 4, 5, 6}
b := []int{2, 3, 5, 7}
differ := New(a, b)
blocks := differ.Blocks()
for _, block := range blocks {
	fmt.Println(block.Tag, gong.StringForSlice(block.Items))
}
Output:

- 1
= 2 3
- 4
= 5
% 7
Example (Strings)
a := strings.Fields("the quick brown fox jumped over the lazy dogs")
b := strings.Fields("a quick red fox jumped over some lazy hogs")
differ := New(a, b)
blocks := differ.Blocks()
for _, block := range blocks {
	fmt.Println(block.Tag, strings.Join(block.Items, " "))
}
Output:

% a
= quick
% red
= fox jumped over
% some
= lazy
% hogs

func (*Differ[T]) Spans

func (me *Differ[T]) Spans() []Span

Spans returns a sequence of Span values representing how to go from a to b. Each span has a Tag and a sequence of [Quad]s. Each Quad holds a pair of start/end indexes into a and b. The easiest method for seeing the differences in two sequences is [Blocks].

type DifferKeyFn added in v1.1.0

type DifferKeyFn[T any] struct {
	A []T
	B []T
	// contains filtered or unexported fields
}

func NewKeyFn added in v1.1.0

func NewKeyFn[T any](a, b []T, keyfn KeyFn[T]) *DifferKeyFn[T]

NewKeyFn returns a DifferKeyFn value based on the provided a and b slices. These slices are only ever read and may be accessed as .A and .B. After creating a DifferKeyFn, call [Blocks] (or [Spans]) to see the differences.

func (*DifferKeyFn[T]) Blocks added in v1.1.0

func (me *DifferKeyFn[T]) Blocks() []BlockKeyFn[T]

Blocks returns a sequence of BlockKeyFn values representing how to go from a to b. Each block has a Tag and a sequence of items. This is the easiest method for seeing the differences in two sequences. See also [Spans].

Example (Namekey)
/*
	type Place struct {
		x    int
		y    int
		name string
	}

	func newPlace(x, y int, name string) Place {
		return Place{x: x, y: y, name: name}
	}

	func (me *Place) String() string {
		return fmt.Sprintf("Place{%d,%d,%q}", me.x, me.y, me.name)
	}
*/ame)
	}
*/
a := []Place{newPlace(1, 2, "foo"), newPlace(3, 4, "bar"),
	newPlace(5, 6, "baz"), newPlace(7, 8, "quux")}
b := []Place{newPlace(1, 2, "foo"), newPlace(6, 2, "baz"),
	newPlace(3, 4, "bar"), newPlace(7, 8, "quux")}
differ := NewKeyFn(a, b, func(p Place) string { return p.name })
blocks := differ.Blocks()
for _, block := range blocks {
	for _, item := range block.Items {
		fmt.Println(block.Tag, item.String())
	}
}
Output:

= Place{1,2,"foo"}
+ Place{6,2,"baz"}
= Place{3,4,"bar"}
- Place{5,6,"baz"}
= Place{7,8,"quux"}
Example (Xkey)
// a: [1 3 5 7]
// b: [1 6 3 7]
a := []Place{newPlace(1, 2, "foo"), newPlace(3, 4, "bar"),
	newPlace(5, 6, "baz"), newPlace(7, 8, "quux")}
b := []Place{newPlace(1, 2, "foo"), newPlace(6, 2, "bar"),
	newPlace(3, 4, "baz"), newPlace(7, 8, "quux")}
differ := NewKeyFn(a, b,
	func(p Place) string { return strconv.Itoa(p.x) })
blocks := differ.Blocks()
for _, block := range blocks {
	for _, item := range block.Items {
		fmt.Println(block.Tag, item.String())
	}
}
Output:

= Place{1,2,"foo"}
+ Place{6,2,"bar"}
= Place{3,4,"baz"}
- Place{5,6,"baz"}
= Place{7,8,"quux"}

func (*DifferKeyFn[T]) Spans added in v1.1.0

func (me *DifferKeyFn[T]) Spans() []Span

Spans returns a sequence of Span values representing how to go from a to b. Each span has a Tag and a sequence of [Quad]s. Each Quad holds a pair of start/end indexes into a and b. The easiest method for seeing the differences in two sequences is [Blocks].

type KeyFn added in v1.1.0

type KeyFn[T any] func(x T) string

type Quad

type Quad struct {
	Astart int
	Aend   int
	Bstart int
	Bend   int
}

type Span

type Span struct {
	Tag Tag
	Quad
}

func (Span) String

func (me Span) String() string

type Tag

type Tag uint8
const (
	Equal Tag = iota
	Insert
	Delete
	Replace
)

func (Tag) String

func (me Tag) String() string

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL