Add regex command implementation
This commit is contained in:
69
internal/regex/engine.go
Normal file
69
internal/regex/engine.go
Normal file
@@ -0,0 +1,69 @@
|
||||
package regex
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"regexp"
|
||||
)
|
||||
|
||||
// Engine encapsulates a compiled regex pattern and parsed template for reuse across candidates.
|
||||
type Engine struct {
|
||||
re *regexp.Regexp
|
||||
tmpl template
|
||||
groups int
|
||||
}
|
||||
|
||||
// NewEngine compiles the regex pattern and template into a reusable Engine instance.
|
||||
func NewEngine(pattern, tmpl string) (*Engine, error) {
|
||||
re, err := regexp.Compile(pattern)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
parsed, maxGroup, err := parseTemplate(tmpl)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if maxGroup > re.NumSubexp() {
|
||||
return nil, ErrTemplateGroupOutOfRange{Group: maxGroup, Available: re.NumSubexp()}
|
||||
}
|
||||
|
||||
return &Engine{
|
||||
re: re,
|
||||
tmpl: parsed,
|
||||
groups: re.NumSubexp(),
|
||||
}, nil
|
||||
}
|
||||
|
||||
// Apply evaluates the regex against input and renders the replacement when it matches.
|
||||
// When no match occurs, matched is false without error.
|
||||
func (e *Engine) Apply(input string) (output string, matchGroups []string, matched bool, err error) {
|
||||
submatches := e.re.FindStringSubmatch(input)
|
||||
if submatches == nil {
|
||||
return "", nil, false, nil
|
||||
}
|
||||
|
||||
rendered, err := e.tmpl.render(submatches)
|
||||
if err != nil {
|
||||
return "", nil, false, err
|
||||
}
|
||||
|
||||
// Exclude the full match from the recorded match group slice.
|
||||
groups := make([]string, 0, len(submatches)-1)
|
||||
if len(submatches) > 1 {
|
||||
groups = append(groups, submatches[1:]...)
|
||||
}
|
||||
|
||||
return rendered, groups, true, nil
|
||||
}
|
||||
|
||||
// ErrTemplateGroupOutOfRange indicates that the template references a capture group that the regex
|
||||
// does not provide.
|
||||
type ErrTemplateGroupOutOfRange struct {
|
||||
Group int
|
||||
Available int
|
||||
}
|
||||
|
||||
func (e ErrTemplateGroupOutOfRange) Error() string {
|
||||
return fmt.Sprintf("template references @%d but pattern only defines %d groups", e.Group, e.Available)
|
||||
}
|
||||
Reference in New Issue
Block a user