refactor(parser/diff): rune based strings compare
This commit is contained in:
parent
37c0d76bf3
commit
29c05f4b36
|
@ -1,46 +0,0 @@
|
||||||
package diff
|
|
||||||
|
|
||||||
// compareStrings compares two strings character by character, optionally ignoring whitespace.
|
|
||||||
func compareStrings(str1, str2 string, compareSpace bool) bool {
|
|
||||||
if compareSpace {
|
|
||||||
return str1 == str2
|
|
||||||
}
|
|
||||||
var i, j int
|
|
||||||
l1 := len(str1)
|
|
||||||
l2 := len(str2)
|
|
||||||
for i < l1 && j < l2 {
|
|
||||||
for i < l1 && isWhitespace(str1[i]) {
|
|
||||||
i++
|
|
||||||
}
|
|
||||||
for j < l2 && isWhitespace(str2[j]) {
|
|
||||||
j++
|
|
||||||
}
|
|
||||||
if i < l1 && j < l2 && str1[i] != str2[j] {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
if i < l1 {
|
|
||||||
i++
|
|
||||||
}
|
|
||||||
if j < l2 {
|
|
||||||
j++
|
|
||||||
}
|
|
||||||
}
|
|
||||||
for i < l1 && isWhitespace(str1[i]) {
|
|
||||||
i++
|
|
||||||
}
|
|
||||||
for j < l2 && isWhitespace(str2[j]) {
|
|
||||||
j++
|
|
||||||
}
|
|
||||||
return i == l1 && j == l2
|
|
||||||
}
|
|
||||||
|
|
||||||
func isWhitespace(b byte) bool {
|
|
||||||
return b == ' ' ||
|
|
||||||
b == '\t' ||
|
|
||||||
b == '\n' ||
|
|
||||||
b == '\r' ||
|
|
||||||
b == '\v' ||
|
|
||||||
b == '\f' ||
|
|
||||||
b == 0x85 ||
|
|
||||||
b == 0xA0
|
|
||||||
}
|
|
|
@ -39,7 +39,7 @@ func (*Diff) Run(results []stage.ExecutorResult, confAny any) (
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, true, err
|
return nil, true, err
|
||||||
}
|
}
|
||||||
isSame := compareStrings(
|
isSame := stringsEqual(
|
||||||
string(answer),
|
string(answer),
|
||||||
result.Files[output.FileName],
|
result.Files[output.FileName],
|
||||||
output.CompareSpace,
|
output.CompareSpace,
|
||||||
|
@ -82,13 +82,13 @@ func (*Diff) Run(results []stage.ExecutorResult, confAny any) (
|
||||||
}
|
}
|
||||||
answerLines := strings.Split(answerStr, "\n")
|
answerLines := strings.Split(answerStr, "\n")
|
||||||
resultLines := strings.Split(resultStr, "\n")
|
resultLines := strings.Split(resultStr, "\n")
|
||||||
diffs := PatienceDiff(
|
diffs := patienceDiff(
|
||||||
answerLines,
|
answerLines,
|
||||||
resultLines,
|
resultLines,
|
||||||
func(a, b string) bool {
|
func(a, b string) bool {
|
||||||
return compareStrings(a, b, output.CompareSpace)
|
return stringsEqual(a, b, output.CompareSpace)
|
||||||
})
|
})
|
||||||
diffOutput := DiffText(diffs)
|
diffOutput := diffText(diffs)
|
||||||
diffOutput = strings.TrimSuffix(diffOutput, "\n ")
|
diffOutput = strings.TrimSuffix(diffOutput, "\n ")
|
||||||
if truncated {
|
if truncated {
|
||||||
diffOutput += "\n\n(truncated)"
|
diffOutput += "\n\n(truncated)"
|
||||||
|
|
|
@ -5,8 +5,44 @@ package diff
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"strings"
|
"strings"
|
||||||
|
"unicode"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// stringsEqual compares two strings character by character, optionally ignoring whitespace.
|
||||||
|
func stringsEqual(str1, str2 string, compareSpace bool) bool {
|
||||||
|
if compareSpace {
|
||||||
|
return str1 == str2
|
||||||
|
}
|
||||||
|
runes1 := []rune(str1)
|
||||||
|
runes2 := []rune(str2)
|
||||||
|
var i, j, l1, l2 int
|
||||||
|
l1 = len(runes1)
|
||||||
|
l2 = len(runes2)
|
||||||
|
for i < l1 && j < l2 {
|
||||||
|
for i < l1 && unicode.IsSpace(runes1[i]) {
|
||||||
|
i++
|
||||||
|
}
|
||||||
|
for j < l2 && unicode.IsSpace(runes2[j]) {
|
||||||
|
j++
|
||||||
|
}
|
||||||
|
if i >= l1 || j >= l2 {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
if runes1[i] != runes2[j] {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
i++
|
||||||
|
j++
|
||||||
|
}
|
||||||
|
for i < l1 && unicode.IsSpace(runes1[i]) {
|
||||||
|
i++
|
||||||
|
}
|
||||||
|
for j < l2 && unicode.IsSpace(runes2[j]) {
|
||||||
|
j++
|
||||||
|
}
|
||||||
|
return i == l1 && j == l2
|
||||||
|
}
|
||||||
|
|
||||||
// DiffType defines the type of a diff element.
|
// DiffType defines the type of a diff element.
|
||||||
type DiffType int8
|
type DiffType int8
|
||||||
|
|
||||||
|
@ -39,8 +75,8 @@ func typeSymbol(t DiffType) string {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// DiffText returns the source and destination texts (all equalities, insertions and deletions).
|
// diffText returns the source and destination texts (all equalities, insertions and deletions).
|
||||||
func DiffText(diffs []DiffLine) string {
|
func diffText(diffs []DiffLine) string {
|
||||||
s := make([]string, len(diffs))
|
s := make([]string, len(diffs))
|
||||||
for i, l := range diffs {
|
for i, l := range diffs {
|
||||||
s[i] = fmt.Sprintf("%s%s", typeSymbol(l.Type), l.Text)
|
s[i] = fmt.Sprintf("%s%s", typeSymbol(l.Type), l.Text)
|
||||||
|
@ -120,8 +156,8 @@ func uniqueElements(a []string) ([]string, []int) {
|
||||||
return elements, indices
|
return elements, indices
|
||||||
}
|
}
|
||||||
|
|
||||||
// PatienceDiff returns the patience diff of two slices of strings.
|
// patienceDiff returns the patience diff of two slices of strings.
|
||||||
func PatienceDiff(a, b []string, equal func(a, b string) bool) []DiffLine {
|
func patienceDiff(a, b []string, equal func(a, b string) bool) []DiffLine {
|
||||||
switch {
|
switch {
|
||||||
case len(a) == 0 && len(b) == 0:
|
case len(a) == 0 && len(b) == 0:
|
||||||
return nil
|
return nil
|
||||||
|
@ -139,7 +175,7 @@ func PatienceDiff(a, b []string, equal func(a, b string) bool) []DiffLine {
|
||||||
if i > 0 {
|
if i > 0 {
|
||||||
return append(
|
return append(
|
||||||
toDiffLines(a[:i], Equal),
|
toDiffLines(a[:i], Equal),
|
||||||
PatienceDiff(a[i:], b[i:], equal)...,
|
patienceDiff(a[i:], b[i:], equal)...,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -150,7 +186,7 @@ func PatienceDiff(a, b []string, equal func(a, b string) bool) []DiffLine {
|
||||||
}
|
}
|
||||||
if j > 0 {
|
if j > 0 {
|
||||||
return append(
|
return append(
|
||||||
PatienceDiff(a[:len(a)-j], b[:len(b)-j], equal),
|
patienceDiff(a[:len(a)-j], b[:len(b)-j], equal),
|
||||||
toDiffLines(a[len(a)-j:], Equal)...,
|
toDiffLines(a[len(a)-j:], Equal)...,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
@ -175,14 +211,14 @@ func PatienceDiff(a, b []string, equal func(a, b string) bool) []DiffLine {
|
||||||
ga, gb := 0, 0
|
ga, gb := 0, 0
|
||||||
for _, ip := range lcs {
|
for _, ip := range lcs {
|
||||||
// PatienceDiff the gaps between the lcs elements.
|
// PatienceDiff the gaps between the lcs elements.
|
||||||
diffs = append(diffs, PatienceDiff(a[ga:ip[0]], b[gb:ip[1]], equal)...)
|
diffs = append(diffs, patienceDiff(a[ga:ip[0]], b[gb:ip[1]], equal)...)
|
||||||
// Append the LCS elements to the diff.
|
// Append the LCS elements to the diff.
|
||||||
diffs = append(diffs, DiffLine{Type: Equal, Text: a[ip[0]]})
|
diffs = append(diffs, DiffLine{Type: Equal, Text: a[ip[0]]})
|
||||||
ga = ip[0] + 1
|
ga = ip[0] + 1
|
||||||
gb = ip[1] + 1
|
gb = ip[1] + 1
|
||||||
}
|
}
|
||||||
// PatienceDiff the remaining elements of a and b after the final LCS element.
|
// PatienceDiff the remaining elements of a and b after the final LCS element.
|
||||||
diffs = append(diffs, PatienceDiff(a[ga:], b[gb:], equal)...)
|
diffs = append(diffs, patienceDiff(a[ga:], b[gb:], equal)...)
|
||||||
|
|
||||||
return diffs
|
return diffs
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue
Block a user