You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
85 lines
1.5 KiB
Go
85 lines
1.5 KiB
Go
package stringx
|
|
|
|
import (
|
|
"sort"
|
|
"strings"
|
|
)
|
|
|
|
// replace more than once to avoid overlapped keywords after replace.
|
|
// only try 2 times to avoid too many or infinite loops.
|
|
const replaceTimes = 2
|
|
|
|
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 {
|
|
for i := 0; i < replaceTimes; i++ {
|
|
var replaced bool
|
|
if text, replaced = r.doReplace(text); !replaced {
|
|
return text
|
|
}
|
|
}
|
|
|
|
return text
|
|
}
|
|
|
|
func (r *replacer) doReplace(text string) (string, bool) {
|
|
chars := []rune(text)
|
|
scopes := r.find(chars)
|
|
if len(scopes) == 0 {
|
|
return text, false
|
|
}
|
|
|
|
sort.Slice(scopes, func(i, j int) bool {
|
|
if scopes[i].start < scopes[j].start {
|
|
return true
|
|
}
|
|
if scopes[i].start == scopes[j].start {
|
|
return scopes[i].stop > scopes[j].stop
|
|
}
|
|
return false
|
|
})
|
|
|
|
var buf strings.Builder
|
|
var index int
|
|
for i := 0; i < len(scopes); i++ {
|
|
scp := &scopes[i]
|
|
if scp.start < index {
|
|
continue
|
|
}
|
|
|
|
buf.WriteString(string(chars[index:scp.start]))
|
|
buf.WriteString(r.mapping[string(chars[scp.start:scp.stop])])
|
|
index = scp.stop
|
|
}
|
|
if index < len(chars) {
|
|
buf.WriteString(string(chars[index:]))
|
|
}
|
|
|
|
return buf.String(), true
|
|
}
|