|
|
|
package stringx
|
|
|
|
|
|
|
|
import (
|
|
|
|
"strings"
|
|
|
|
)
|
|
|
|
|
|
|
|
type (
|
|
|
|
// Replacer interface wraps the Replace method.
|
|
|
|
Replacer interface {
|
|
|
|
Replace(text string) string
|
|
|
|
}
|
|
|
|
|
|
|
|
replacer struct {
|
|
|
|
*node
|
|
|
|
mapping map[string]string
|
|
|
|
}
|
|
|
|
)
|
|
|
|
|
|
|
|
// NewReplacer returns a Replacer.
|
|
|
|
func NewReplacer(mapping map[string]string) Replacer {
|
|
|
|
rep := &replacer{
|
|
|
|
node: new(node),
|
|
|
|
mapping: mapping,
|
|
|
|
}
|
|
|
|
for k := range mapping {
|
|
|
|
rep.add(k)
|
|
|
|
}
|
|
|
|
rep.build()
|
|
|
|
|
|
|
|
return rep
|
|
|
|
}
|
|
|
|
|
|
|
|
// 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
|
|
|
|
|
|
|
|
for len(target) != 0 {
|
|
|
|
uselessLen, matchLen, nextPaths := cur.longestMatch(target, paths)
|
|
|
|
if uselessLen > 0 {
|
|
|
|
buf.WriteString(string(target[:uselessLen]))
|
|
|
|
target = target[uselessLen:]
|
|
|
|
}
|
|
|
|
if matchLen > 0 {
|
|
|
|
replaced := r.mapping[string(target[:matchLen])]
|
|
|
|
target = append([]rune(replaced), target[matchLen:]...)
|
|
|
|
}
|
|
|
|
if len(nextPaths) != 0 {
|
|
|
|
cur = nextPaths[len(nextPaths)-1]
|
|
|
|
paths = nextPaths
|
|
|
|
} else {
|
|
|
|
cur = r.node
|
|
|
|
paths = nil
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return buf.String()
|
|
|
|
}
|