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:
@@ -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
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user