114 lines
2.3 KiB
Go
114 lines
2.3 KiB
Go
|
package replace
|
||
|
|
||
|
type Node struct {
|
||
|
children map[rune]*Node
|
||
|
output int
|
||
|
fail *Node
|
||
|
}
|
||
|
|
||
|
func NewNode() *Node {
|
||
|
return &Node{
|
||
|
children: make(map[rune]*Node),
|
||
|
output: -1,
|
||
|
fail: nil,
|
||
|
}
|
||
|
}
|
||
|
|
||
|
type CommentzWalter struct {
|
||
|
root *Node
|
||
|
patterns []string
|
||
|
replacements map[int]string
|
||
|
}
|
||
|
|
||
|
func NewCommentzWalter() *CommentzWalter {
|
||
|
return &CommentzWalter{
|
||
|
root: NewNode(),
|
||
|
patterns: make([]string, 0),
|
||
|
replacements: make(map[int]string),
|
||
|
}
|
||
|
}
|
||
|
|
||
|
func (cw *CommentzWalter) AddPattern(pattern string, replacement string) {
|
||
|
cw.patterns = append(cw.patterns, pattern)
|
||
|
idx := len(cw.patterns) - 1
|
||
|
cw.replacements[idx] = replacement
|
||
|
}
|
||
|
|
||
|
func (cw *CommentzWalter) BuildMatchingMachine() {
|
||
|
for idx, pattern := range cw.patterns {
|
||
|
current := cw.root
|
||
|
for _, char := range pattern {
|
||
|
if _, exists := current.children[char]; !exists {
|
||
|
current.children[char] = NewNode()
|
||
|
}
|
||
|
current = current.children[char]
|
||
|
}
|
||
|
current.output = idx
|
||
|
}
|
||
|
|
||
|
queue := make([]*Node, 0)
|
||
|
for _, node := range cw.root.children {
|
||
|
queue = append(queue, node)
|
||
|
node.fail = cw.root
|
||
|
}
|
||
|
|
||
|
for len(queue) > 0 {
|
||
|
r := queue[0]
|
||
|
queue = queue[1:]
|
||
|
|
||
|
for char, child := range r.children {
|
||
|
queue = append(queue, child)
|
||
|
failNode := r.fail
|
||
|
for failNode != nil && failNode.children[char] == nil {
|
||
|
failNode = failNode.fail
|
||
|
}
|
||
|
|
||
|
if failNode == nil {
|
||
|
child.fail = cw.root
|
||
|
} else {
|
||
|
child.fail = failNode.children[char]
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
func (cw *CommentzWalter) CommentzWalterReplace(text string) string {
|
||
|
matches := make([]string, 0)
|
||
|
current := cw.root
|
||
|
runes := []rune(text)
|
||
|
replaced := make([]rune, 0)
|
||
|
|
||
|
for i, char := range runes {
|
||
|
for current != nil && current.children[char] == nil {
|
||
|
current = current.fail
|
||
|
}
|
||
|
|
||
|
if current == nil {
|
||
|
current = cw.root
|
||
|
replaced = append(replaced, runes[i])
|
||
|
continue
|
||
|
}
|
||
|
|
||
|
current = current.children[char]
|
||
|
if current.output != -1 {
|
||
|
matchIdx := current.output
|
||
|
matches = append(matches, cw.replacements[matchIdx])
|
||
|
replRunes := []rune(cw.replacements[matchIdx])
|
||
|
|
||
|
for _, rn := range replRunes {
|
||
|
replaced = append(replaced, rn)
|
||
|
}
|
||
|
|
||
|
patternLen := len(cw.patterns[matchIdx])
|
||
|
replaceLen := len(cw.replacements[matchIdx])
|
||
|
if (patternLen > replaceLen) {
|
||
|
// Skip index to after the pattern
|
||
|
dif := patternLen - replaceLen
|
||
|
i = i + dif
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return string(replaced)
|
||
|
}
|