introduced mutators
This commit is contained in:
parent
9f51afa15f
commit
86ac1ebcf2
89
main.go
89
main.go
@ -18,8 +18,21 @@ var (
|
|||||||
// format string with {0} as placeholders
|
// format string with {0} as placeholders
|
||||||
// {0} always matches the whole line
|
// {0} always matches the whole line
|
||||||
// {1} and onwards match their respective sub groups
|
// {1} and onwards match their respective sub groups
|
||||||
|
//
|
||||||
// You can optionally specify a printf-syntax for formatting like this: {1:%s} or {1:%02d}
|
// You can optionally specify a printf-syntax for formatting like this: {1:%s} or {1:%02d}
|
||||||
// printf-syntax is currently supported for: strings, floats, integers
|
// printf-syntax is currently supported for: strings, floats, integers.
|
||||||
|
//
|
||||||
|
// Addtionally mutators can be provided
|
||||||
|
// to further manipulate the value using the given syntax: {1:%d:+1}
|
||||||
|
//
|
||||||
|
// The value mutated by can also be a back reference to another group
|
||||||
|
// using round brackets like this: {1:%d:+(2)}}
|
||||||
|
//
|
||||||
|
// Multiple mutators can be used at once: {1:%d:+2*3-(2)}
|
||||||
|
// Be aware that they will be applied strictly from left to right!
|
||||||
|
//
|
||||||
|
// The following number mutators (integers and floats) are allowed:
|
||||||
|
// + - * / ^ %
|
||||||
output = flag.String("o", "{0}", "output pattern")
|
output = flag.String("o", "{0}", "output pattern")
|
||||||
|
|
||||||
// don't ignore lines which do not match against input.
|
// don't ignore lines which do not match against input.
|
||||||
@ -31,7 +44,9 @@ var (
|
|||||||
// it may be useful to have a boolean flag for this behavior
|
// it may be useful to have a boolean flag for this behavior
|
||||||
lineParseAmount = flag.Int("n", 1, "amount of lines to feed into input pattern")
|
lineParseAmount = flag.Int("n", 1, "amount of lines to feed into input pattern")
|
||||||
|
|
||||||
replacePattern = regexp.MustCompile(`\{(\d+)(?::(.*?))?\}`)
|
replacePattern = regexp.MustCompile(`\{(\d+)(?::(.*?))?(?::(.*?))?\}`)
|
||||||
|
|
||||||
|
numMutationPattern = regexp.MustCompile(`([+\-*/])(\d+|\((\d+)\))`)
|
||||||
)
|
)
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
@ -100,10 +115,12 @@ func replaceVars(format string, vars ...string) string {
|
|||||||
|
|
||||||
if strings.HasSuffix(rplFmt, "d") { // replace integers
|
if strings.HasSuffix(rplFmt, "d") { // replace integers
|
||||||
value, _ := strconv.ParseInt(vars[varIndex], 10, 64)
|
value, _ := strconv.ParseInt(vars[varIndex], 10, 64)
|
||||||
format = strings.Replace(format, rplStr, fmt.Sprintf(rplFmt, value), 1)
|
mutate := numMut2func[int64](replacement[3])
|
||||||
|
format = strings.Replace(format, rplStr, fmt.Sprintf(rplFmt, mutate(value, vars)), 1)
|
||||||
} else if strings.HasSuffix(rplFmt, "f") { // replace floats
|
} else if strings.HasSuffix(rplFmt, "f") { // replace floats
|
||||||
value, _ := strconv.ParseFloat(vars[varIndex], 64)
|
value, _ := strconv.ParseFloat(vars[varIndex], 64)
|
||||||
format = strings.Replace(format, rplStr, fmt.Sprintf(rplFmt, value), 1)
|
mutate := numMut2func[float64](replacement[3])
|
||||||
|
format = strings.Replace(format, rplStr, fmt.Sprintf(rplFmt, mutate(value, vars)), 1)
|
||||||
} else { // replace strings
|
} else { // replace strings
|
||||||
format = strings.Replace(format, rplStr, fmt.Sprintf(rplFmt, vars[varIndex]), 1)
|
format = strings.Replace(format, rplStr, fmt.Sprintf(rplFmt, vars[varIndex]), 1)
|
||||||
}
|
}
|
||||||
@ -112,3 +129,67 @@ func replaceVars(format string, vars ...string) string {
|
|||||||
|
|
||||||
return format
|
return format
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var numMutatorCache = map[string]interface{}{}
|
||||||
|
|
||||||
|
func numMut2func[T int64 | float64](mutation string) (f func(value T, vars []string) T) {
|
||||||
|
if mutation == "" {
|
||||||
|
return func(value T, vars []string) T { return value }
|
||||||
|
}
|
||||||
|
|
||||||
|
// caching
|
||||||
|
if v, ok := numMutatorCache[mutation]; ok {
|
||||||
|
return v.(func(value T, vars []string) T)
|
||||||
|
}
|
||||||
|
defer func() { numMutatorCache[mutation] = f }()
|
||||||
|
|
||||||
|
matches := numMutationPattern.FindAllStringSubmatch(mutation, -1)
|
||||||
|
mutators := make([]NumMutator, 0, len(matches))
|
||||||
|
var err error
|
||||||
|
for _, match := range matches {
|
||||||
|
mut := NumMutator{Op: NewNumOperatorFromString(match[1])}
|
||||||
|
if match[3] == "" {
|
||||||
|
mut.Value, err = strconv.Atoi(match[2])
|
||||||
|
mut.Var = false
|
||||||
|
if err != nil {
|
||||||
|
panic("invalid number in number mutator: " + match[2])
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
mut.Var = true
|
||||||
|
mut.Value, err = strconv.Atoi(match[3])
|
||||||
|
if err != nil {
|
||||||
|
panic("invalid back reference group in number mutator: " + match[2])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
mutators = append(mutators, mut)
|
||||||
|
}
|
||||||
|
|
||||||
|
return func(value T, vars []string) T {
|
||||||
|
for _, mutator := range mutators {
|
||||||
|
var otherValue T
|
||||||
|
if mutator.Var {
|
||||||
|
other, err := strconv.Atoi(vars[mutator.Value])
|
||||||
|
if err != nil {
|
||||||
|
panic("back reference group for number mutator is not a number")
|
||||||
|
}
|
||||||
|
otherValue = T(other)
|
||||||
|
} else {
|
||||||
|
otherValue = T(mutator.Value)
|
||||||
|
}
|
||||||
|
|
||||||
|
switch mutator.Op {
|
||||||
|
case NumOperatorAdd:
|
||||||
|
value += otherValue
|
||||||
|
case NumOperatorSub:
|
||||||
|
value -= otherValue
|
||||||
|
case NumOperatorMul:
|
||||||
|
value *= otherValue
|
||||||
|
case NumOperatorDiv:
|
||||||
|
value /= otherValue
|
||||||
|
default:
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return value
|
||||||
|
}
|
||||||
|
}
|
||||||
|
31
mutator.go
Normal file
31
mutator.go
Normal file
@ -0,0 +1,31 @@
|
|||||||
|
package main
|
||||||
|
|
||||||
|
type NumMutator struct {
|
||||||
|
Op NumOperator
|
||||||
|
Var bool
|
||||||
|
Value int
|
||||||
|
}
|
||||||
|
|
||||||
|
type NumOperator string
|
||||||
|
|
||||||
|
const (
|
||||||
|
NumOperatorAdd NumOperator = "+"
|
||||||
|
NumOperatorSub NumOperator = "-"
|
||||||
|
NumOperatorMul NumOperator = "*"
|
||||||
|
NumOperatorDiv NumOperator = "/"
|
||||||
|
)
|
||||||
|
|
||||||
|
func NewNumOperatorFromString(str string) NumOperator {
|
||||||
|
switch str {
|
||||||
|
case "+":
|
||||||
|
return NumOperatorAdd
|
||||||
|
case "-":
|
||||||
|
return NumOperatorSub
|
||||||
|
case "*":
|
||||||
|
return NumOperatorMul
|
||||||
|
case "/":
|
||||||
|
return NumOperatorDiv
|
||||||
|
default:
|
||||||
|
panic("invalid number operator: " + str)
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user