intrange.go 2.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121
  1. package types
  2. import (
  3. "strconv"
  4. "strings"
  5. "unicode"
  6. )
  7. // IntRange stores a max and min amount for range
  8. type IntRange struct {
  9. min int
  10. max int
  11. }
  12. // IntRanges is a slice of IntRange
  13. type IntRanges []IntRange
  14. func makeIntRange(min, max int) IntRange {
  15. return IntRange{
  16. min,
  17. max,
  18. }
  19. }
  20. // Get returns true if the argument n is included in the closed range
  21. // between min and max
  22. func (r IntRange) Get(n int) bool {
  23. return n >= r.min && n <= r.max
  24. }
  25. // Get returns true if the argument n is included in the closed range
  26. // between min and max of any of the provided IntRanges
  27. func (rs IntRanges) Get(n int) bool {
  28. for _, r := range rs {
  29. if r.Get(n) {
  30. return true
  31. }
  32. }
  33. return false
  34. }
  35. // Min returns min value between a and b
  36. func Min(a, b int) int {
  37. if a < b {
  38. return a
  39. }
  40. return b
  41. }
  42. // Max returns max value between a and b
  43. func Max(a, b int) int {
  44. if a < b {
  45. return b
  46. }
  47. return a
  48. }
  49. // ParseNumberMenu parses input for number menus split by spaces or commas
  50. //supports individual selection: 1 2 3 4
  51. //supports range selections: 1-4 10-20
  52. //supports negation: ^1 ^1-4
  53. //
  54. //include and excule holds numbers that should be added and should not be added
  55. //respectively. other holds anything that can't be parsed as an int. This is
  56. //intended to allow words inside of number menus. e.g. 'all' 'none' 'abort'
  57. //of course the implementation is up to the caller, this function mearley parses
  58. //the input and organizes it
  59. func ParseNumberMenu(input string) (IntRanges, IntRanges, StringSet, StringSet) {
  60. include := make(IntRanges, 0)
  61. exclude := make(IntRanges, 0)
  62. otherInclude := make(StringSet)
  63. otherExclude := make(StringSet)
  64. words := strings.FieldsFunc(input, func(c rune) bool {
  65. return unicode.IsSpace(c) || c == ','
  66. })
  67. for _, word := range words {
  68. var num1 int
  69. var num2 int
  70. var err error
  71. invert := false
  72. other := otherInclude
  73. if word[0] == '^' {
  74. invert = true
  75. other = otherExclude
  76. word = word[1:]
  77. }
  78. ranges := strings.SplitN(word, "-", 2)
  79. num1, err = strconv.Atoi(ranges[0])
  80. if err != nil {
  81. other.Set(strings.ToLower(word))
  82. continue
  83. }
  84. if len(ranges) == 2 {
  85. num2, err = strconv.Atoi(ranges[1])
  86. if err != nil {
  87. other.Set(strings.ToLower(word))
  88. continue
  89. }
  90. } else {
  91. num2 = num1
  92. }
  93. mi := Min(num1, num2)
  94. ma := Max(num1, num2)
  95. if !invert {
  96. include = append(include, makeIntRange(mi, ma))
  97. } else {
  98. exclude = append(exclude, makeIntRange(mi, ma))
  99. }
  100. }
  101. return include, exclude, otherInclude, otherExclude
  102. }