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