package main import ( "fmt" "math" "strconv" ) type numRange struct { start int end int } // Returns the exponent of the closest power of 10 smaller // than the given value. func floorPower10(val int) int { return int(math.Floor(math.Log10(float64(val)))) } // Returns smallest multiple of 10^exp, that is greater than val func roundUpToNearest10Multiple(val int, exp int) int { bench := int(math.Round(math.Pow10(exp))) if val != 0 && val%bench == 0 { return val } else { return (bench - val%bench) + val } } func roundDownToNearest10Multiple(val int, exp int) int { bench := int(math.Round(math.Pow10(exp))) return val - val%bench } // Converts the given integer into an int-slice, where each element // represents a digit of the number. func intToSlc(val int) []int { valStr := strconv.Itoa(val) valSlc := []rune(valStr) toRet := make([]int, len(valStr)) for i, r := range valSlc { toRet[i] = int(r - 48) } return toRet } func range2regex(start int, end int) string { rangeStart := start rangeEnd := end if rangeStart > rangeEnd { panic("Range start greater than range end.") } ranges := make([]numRange, 0) // If both numbers are in the same power of 10 eg. 15000 and 17000. // the maximum power of 10 that we will go to, is determined by the largest // power of 10 at which both numbers differ. Given 15000 and 17000, we will // go up to 10^3, because that is the largestindex at which they differ. startRangeSlc := intToSlc(rangeStart) endRangeSlc := intToSlc(rangeEnd) maxPower10 := 0 if len(startRangeSlc) != len(endRangeSlc) { // Different number of digits, so we will go up to the maximum (which must be rangeEnd) maxPower10 = floorPower10(rangeEnd) // Maximum power of 10 that we will reach } else { maxPower10 = 0 for i := range startRangeSlc { if startRangeSlc[i] != endRangeSlc[i] { maxPower10 = len(startRangeSlc) - i - 1 break } } } tmp := rangeStart exp := 1 // The exponent of 10 that we are finding the range to // Increasing up to highest power for exp <= maxPower10 { tmpRangeEnd := roundUpToNearest10Multiple(tmp, exp) if tmp != tmpRangeEnd { ranges = append(ranges, numRange{tmp, tmpRangeEnd - 1}) } tmp = tmpRangeEnd exp++ } exp-- // Decreasing down to lowest power for exp >= 1 { tmpRangeEnd := roundDownToNearest10Multiple(rangeEnd, exp) if tmp != tmpRangeEnd { ranges = append(ranges, numRange{tmp, tmpRangeEnd - 1}) } tmp = tmpRangeEnd exp-- } // Last range - tmp to rangeEnd ranges = append(ranges, numRange{tmp, rangeEnd}) regex := "(" // Generate the regex for i, rg := range ranges { if i > 0 { regex += "|" } regex += "(" startSlc := intToSlc(rg.start) endSlc := intToSlc(rg.end) if len(startSlc) != len(endSlc) { panic("Ranges have unequal lengths.") } for i := range startSlc { if startSlc[i] == endSlc[i] { regex += string(rune(startSlc[i] + 48)) // '0' is ascii value 48, 1 is 49 etc. To convert the digit to its character form, we can just add 48. } else { regex += fmt.Sprintf("[%c-%c]", rune(startSlc[i]+48), rune(endSlc[i]+48)) } } regex += ")" } regex += ")" return regex }