|
@@ -1,6 +1,8 @@
|
|
|
package stringx
|
|
|
|
|
|
-import "strings"
|
|
|
+import (
|
|
|
+ "bytes"
|
|
|
+)
|
|
|
|
|
|
type (
|
|
|
// Replacer interface wraps the Replace method.
|
|
@@ -30,68 +32,27 @@ func NewReplacer(mapping map[string]string) Replacer {
|
|
|
|
|
|
// Replace replaces text with given substitutes.
|
|
|
func (r *replacer) Replace(text string) string {
|
|
|
- var builder strings.Builder
|
|
|
- var start int
|
|
|
- chars := []rune(text)
|
|
|
- size := len(chars)
|
|
|
-
|
|
|
- for start < size {
|
|
|
- cur := r.node
|
|
|
-
|
|
|
- if start > 0 {
|
|
|
- builder.WriteString(string(chars[:start]))
|
|
|
- }
|
|
|
-
|
|
|
- for i := start; i < size; i++ {
|
|
|
- child, ok := cur.children[chars[i]]
|
|
|
- if ok {
|
|
|
- cur = child
|
|
|
- } else if cur == r.node {
|
|
|
- builder.WriteRune(chars[i])
|
|
|
- // cur already points to root, set start only
|
|
|
- start = i + 1
|
|
|
- continue
|
|
|
+ var buf bytes.Buffer
|
|
|
+ target := []rune(text)
|
|
|
+ cur := r.node
|
|
|
+ nextStart := 0
|
|
|
+ for len(target) != 0 {
|
|
|
+ used, jump, matched := cur.longestMatch(target, nextStart)
|
|
|
+ if matched {
|
|
|
+ replaced := r.mapping[string(target[:used])]
|
|
|
+ target = append([]rune(replaced), target[used:]...)
|
|
|
+ cur = r.node
|
|
|
+ } else {
|
|
|
+ buf.WriteString(string(target[:used]))
|
|
|
+ target = target[used:]
|
|
|
+ if jump != nil {
|
|
|
+ cur = jump
|
|
|
+ nextStart = jump.depth
|
|
|
} else {
|
|
|
- curDepth := cur.depth
|
|
|
- cur = cur.fail
|
|
|
- child, ok = cur.children[chars[i]]
|
|
|
- if !ok {
|
|
|
- // write this path
|
|
|
- builder.WriteString(string(chars[i-curDepth : i+1]))
|
|
|
- // go to root
|
|
|
- cur = r.node
|
|
|
- start = i + 1
|
|
|
- continue
|
|
|
- }
|
|
|
-
|
|
|
- failDepth := cur.depth
|
|
|
- // write path before jump
|
|
|
- builder.WriteString(string(chars[start : start+curDepth-failDepth]))
|
|
|
- start += curDepth - failDepth
|
|
|
- cur = child
|
|
|
- }
|
|
|
-
|
|
|
- if cur.end {
|
|
|
- val := string(chars[i+1-cur.depth : i+1])
|
|
|
- builder.WriteString(r.mapping[val])
|
|
|
- builder.WriteString(string(chars[i+1:]))
|
|
|
- // only matching this path, all previous paths are done
|
|
|
- if start >= i+1-cur.depth && i+1 >= size {
|
|
|
- return builder.String()
|
|
|
- }
|
|
|
-
|
|
|
- chars = []rune(builder.String())
|
|
|
- size = len(chars)
|
|
|
- builder.Reset()
|
|
|
- break
|
|
|
+ cur = r.node
|
|
|
+ nextStart = 0
|
|
|
}
|
|
|
}
|
|
|
-
|
|
|
- if !cur.end {
|
|
|
- builder.WriteString(string(chars[start:]))
|
|
|
- return builder.String()
|
|
|
- }
|
|
|
}
|
|
|
-
|
|
|
- return string(chars)
|
|
|
+ return buf.String()
|
|
|
}
|