introduced mutators
This commit is contained in:
		
							
								
								
									
										89
									
								
								main.go
									
									
									
									
									
								
							
							
						
						
									
										89
									
								
								main.go
									
									
									
									
									
								
							@ -18,8 +18,21 @@ var (
 | 
			
		||||
	// format string with {0} as placeholders
 | 
			
		||||
	// {0} always matches the whole line
 | 
			
		||||
	// {1} and onwards match their respective sub groups
 | 
			
		||||
	//
 | 
			
		||||
	// 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")
 | 
			
		||||
 | 
			
		||||
	// 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
 | 
			
		||||
	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() {
 | 
			
		||||
@ -100,10 +115,12 @@ func replaceVars(format string, vars ...string) string {
 | 
			
		||||
 | 
			
		||||
		if strings.HasSuffix(rplFmt, "d") { // replace integers
 | 
			
		||||
			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
 | 
			
		||||
			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
 | 
			
		||||
			format = strings.Replace(format, rplStr, fmt.Sprintf(rplFmt, vars[varIndex]), 1)
 | 
			
		||||
		}
 | 
			
		||||
@ -112,3 +129,67 @@ func replaceVars(format string, vars ...string) string {
 | 
			
		||||
 | 
			
		||||
	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)
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
		Reference in New Issue
	
	Block a user