refactor: simplify stringx.Replacer, and avoid potential infinite loops (#2877)

* simplify replace

* backup

* refactor: simplify stringx.Replacer

* chore: add comments and const

* chore: add more tests

* chore: rename variable
This commit is contained in:
Kevin Wan
2023-02-14 10:18:02 +08:00
committed by GitHub
parent 9be17a2d28
commit cddf3875cf
4 changed files with 56 additions and 354 deletions

View File

@@ -96,101 +96,3 @@ func (n *node) find(chars []rune) []scope {
return scopes
}
func (n *node) longestMatch(chars []rune, paths []*node) (uselessLen, matchLen int, nextPaths []*node) {
cur := n
var longestMatched *node
for i := len(paths); i < len(chars); i++ {
char := chars[i]
child, ok := cur.children[char]
if ok {
cur = child
if cur.end {
longestMatched = cur
}
paths = append(paths, cur)
} else {
if longestMatched != nil {
return 0, longestMatched.depth, nil
}
if n.end {
return 0, n.depth, nil
}
// new path match
var jump *node
// old path pre longest preMatch
preMatch, preStart := findMatch(paths)
icur := cur
for icur.fail != nil {
jump, ok = icur.fail.children[char]
if ok {
break
}
icur = icur.fail
}
switch {
case preMatch != nil && jump != nil:
if jumpStart := i - jump.depth + 1; preStart < jumpStart {
return preStart, preMatch.depth, nil
} else {
return jumpStart, 0, append(paths[jumpStart:], jump)
}
case preMatch != nil && jump == nil:
return preStart, preMatch.depth, nil
case preMatch == nil && jump != nil:
return i - jump.depth + 1, 0, append(paths[i-jump.depth+1:], jump)
case preMatch == nil && jump == nil:
return i + 1, 0, nil
}
}
}
// this longest matched node
if longestMatched != nil {
return 0, longestMatched.depth, nil
}
if n.end {
return 0, n.depth, nil
}
match, start := findMatch(paths)
if match != nil {
return start, match.depth, nil
}
return len(chars), 0, nil
}
func findMatch(path []*node) (*node, int) {
var result *node
var start int
for i := len(path) - 1; i >= 0; i-- {
icur := path[i]
var cur *node
for icur.fail != nil {
if icur.fail.end {
cur = icur.fail
break
}
icur = icur.fail
}
if cur != nil {
if result == nil {
result = cur
start = i - result.depth + 1
} else if curStart := i - cur.depth + 1; curStart < start {
result = cur
start = curStart
}
}
}
return result, start
}