chore: refactor (#2875)
This commit is contained in:
@@ -100,33 +100,6 @@ func (n *node) find(chars []rune) []scope {
|
||||
func (n *node) longestMatch(chars []rune, paths []*node) (uselessLen, matchLen int, nextPaths []*node) {
|
||||
cur := n
|
||||
var longestMatched *node
|
||||
findMatch := func(path []*node) (*node, int) {
|
||||
var (
|
||||
result *node
|
||||
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
|
||||
}
|
||||
|
||||
for i := len(paths); i < len(chars); i++ {
|
||||
char := chars[i]
|
||||
@@ -141,21 +114,25 @@ func (n *node) longestMatch(chars []rune, paths []*node) (uselessLen, matchLen i
|
||||
if longestMatched != nil {
|
||||
return 0, longestMatched.depth, nil
|
||||
}
|
||||
|
||||
if n.end {
|
||||
return 0, n.depth, nil
|
||||
}
|
||||
// old path pre longest preMatch
|
||||
preMatch, preStart := findMatch(paths)
|
||||
|
||||
// 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 {
|
||||
@@ -172,16 +149,48 @@ func (n *node) longestMatch(chars []rune, paths []*node) (uselessLen, matchLen i
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 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
|
||||
}
|
||||
|
||||
@@ -33,9 +33,10 @@ func NewReplacer(mapping map[string]string) Replacer {
|
||||
// Replace replaces text with given substitutes.
|
||||
func (r *replacer) Replace(text string) string {
|
||||
var buf strings.Builder
|
||||
var paths []*node
|
||||
target := []rune(text)
|
||||
cur := r.node
|
||||
var paths []*node
|
||||
|
||||
for len(target) != 0 {
|
||||
uselessLen, matchLen, nextPaths := cur.longestMatch(target, paths)
|
||||
if uselessLen > 0 {
|
||||
@@ -54,5 +55,6 @@ func (r *replacer) Replace(text string) string {
|
||||
paths = nil
|
||||
}
|
||||
}
|
||||
|
||||
return buf.String()
|
||||
}
|
||||
|
||||
@@ -211,3 +211,11 @@ func TestFuzzReplacerCase2(t *testing.T) {
|
||||
t.Errorf("result: %s, match: %v", val, keys)
|
||||
}
|
||||
}
|
||||
|
||||
func TestReplacer_ReplaceLongestMatch(t *testing.T) {
|
||||
replacer := NewReplacer(map[string]string{
|
||||
"日本的首都": "东京",
|
||||
"日本": "本日",
|
||||
})
|
||||
assert.Equal(t, "东京是东京", replacer.Replace("日本的首都是东京"))
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user