fixed compare behaviour

This commit is contained in:
2026-04-24 16:32:45 +06:00
parent 9861e09246
commit 5f753c3e93
3 changed files with 126 additions and 4 deletions

View File

@@ -1103,14 +1103,18 @@ func (j *JSONLFile) valuesMatch(a, b any, strictCompare bool) bool {
return a == b
}
// Для строк - нечувствительное к регистру сравнение
if a == b {
return true
}
// Для строк - нечувствительное к регистру сравнение (равенство, не подстрока)
if aStr, ok := a.(string); ok {
if bStr, ok := b.(string); ok {
return strings.Contains(strings.ToLower(aStr), strings.ToLower(bStr))
return matchStringByPattern(aStr, bStr, strictCompare)
}
}
return a == b
return false
}
// rewriteFile перезаписывает файл новыми данными

View File

@@ -1474,7 +1474,7 @@ func (db *LineDb) valuesMatch(a, b any, strictCompare bool) bool {
// Сравнение строк
if aStr, ok := a.(string); ok {
if bStr, ok := b.(string); ok {
return strings.EqualFold(aStr, bStr)
return matchStringByPattern(aStr, bStr, strictCompare)
}
}

118
pkg/linedb/string_match.go Normal file
View File

@@ -0,0 +1,118 @@
package linedb
import "strings"
type stringMatchMode int
const (
stringMatchEqual stringMatchMode = iota
stringMatchContains
stringMatchHasPrefix
stringMatchHasSuffix
)
func matchStringByPattern(value string, pattern string, strictCompare bool) bool {
mode, lit := parsePercentPattern(pattern)
if !strictCompare {
// For substring checks we use ToLower (close enough to EqualFold intent).
value = strings.ToLower(value)
lit = strings.ToLower(lit)
}
switch mode {
case stringMatchContains:
return strings.Contains(value, lit)
case stringMatchHasPrefix:
return strings.HasPrefix(value, lit)
case stringMatchHasSuffix:
return strings.HasSuffix(value, lit)
default:
if strictCompare {
return value == lit
}
return strings.EqualFold(value, lit)
}
}
// parsePercentPattern interprets unescaped % at the start/end of pattern:
// - %foo% => contains "foo"
// - foo% => hasPrefix "foo"
// - %foo => hasSuffix "foo"
// - foo => equal "foo"
// Escaping: \% means literal %, \\ means literal \ (only affects escape processing).
func parsePercentPattern(pattern string) (stringMatchMode, string) {
if pattern == "" {
return stringMatchEqual, ""
}
leading := pattern[0] == '%'
trailing := len(pattern) > 0 && pattern[len(pattern)-1] == '%' && !isEscapedAt(pattern, len(pattern)-1)
start := 0
end := len(pattern)
if leading {
start = 1
}
if trailing && end > start {
end--
}
lit := unescapePercents(pattern[start:end])
switch {
case leading && trailing:
return stringMatchContains, lit
case trailing:
return stringMatchHasPrefix, lit
case leading:
return stringMatchHasSuffix, lit
default:
return stringMatchEqual, unescapePercents(pattern)
}
}
func isEscapedAt(s string, idx int) bool {
// idx is escaped if preceded by an odd number of backslashes.
if idx <= 0 || idx >= len(s) {
return false
}
n := 0
for i := idx - 1; i >= 0 && s[i] == '\\'; i-- {
n++
}
return n%2 == 1
}
func unescapePercents(s string) string {
if s == "" {
return ""
}
var b strings.Builder
b.Grow(len(s))
esc := false
for i := 0; i < len(s); i++ {
ch := s[i]
if esc {
// Only unescape % and \; keep backslash for other chars.
if ch == '%' || ch == '\\' {
b.WriteByte(ch)
} else {
b.WriteByte('\\')
b.WriteByte(ch)
}
esc = false
continue
}
if ch == '\\' {
esc = true
continue
}
b.WriteByte(ch)
}
if esc {
// dangling backslash
b.WriteByte('\\')
}
return b.String()
}