intrange.go 2.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146
  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. func intRangesEqual(a, b IntRanges) bool {
  50. if a == nil && b == nil {
  51. return true
  52. }
  53. if a == nil || b == nil {
  54. return false
  55. }
  56. if len(a) != len(b) {
  57. return false
  58. }
  59. for n := range a {
  60. r1 := a[n]
  61. r2 := b[n]
  62. if r1.min != r2.min || r1.max != r2.max {
  63. return false
  64. }
  65. }
  66. return true
  67. }
  68. // ParseNumberMenu parses input for number menus split by spaces or commas
  69. //supports individual selection: 1 2 3 4
  70. //supports range selections: 1-4 10-20
  71. //supports negation: ^1 ^1-4
  72. //
  73. //include and excule holds numbers that should be added and should not be added
  74. //respectively. other holds anything that can't be parsed as an int. This is
  75. //intended to allow words inside of number menus. e.g. 'all' 'none' 'abort'
  76. //of course the implementation is up to the caller, this function mearley parses
  77. //the input and organizes it
  78. func ParseNumberMenu(input string) (IntRanges, IntRanges, StringSet, StringSet) {
  79. include := make(IntRanges, 0)
  80. exclude := make(IntRanges, 0)
  81. otherInclude := make(StringSet)
  82. otherExclude := make(StringSet)
  83. words := strings.FieldsFunc(input, func(c rune) bool {
  84. return unicode.IsSpace(c) || c == ','
  85. })
  86. for _, word := range words {
  87. var num1 int
  88. var num2 int
  89. var err error
  90. invert := false
  91. other := otherInclude
  92. if word[0] == '^' {
  93. invert = true
  94. other = otherExclude
  95. word = word[1:]
  96. }
  97. ranges := strings.SplitN(word, "-", 2)
  98. num1, err = strconv.Atoi(ranges[0])
  99. if err != nil {
  100. other.Set(strings.ToLower(word))
  101. continue
  102. }
  103. if len(ranges) == 2 {
  104. num2, err = strconv.Atoi(ranges[1])
  105. if err != nil {
  106. other.Set(strings.ToLower(word))
  107. continue
  108. }
  109. } else {
  110. num2 = num1
  111. }
  112. mi := Min(num1, num2)
  113. ma := Max(num1, num2)
  114. if !invert {
  115. include = append(include, makeIntRange(mi, ma))
  116. } else {
  117. exclude = append(exclude, makeIntRange(mi, ma))
  118. }
  119. }
  120. return include, exclude, otherInclude, otherExclude
  121. }