util.go 5.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196
  1. package parse // import "github.com/tdewolff/parse"
  2. // Copy returns a copy of the given byte slice.
  3. func Copy(src []byte) (dst []byte) {
  4. dst = make([]byte, len(src))
  5. copy(dst, src)
  6. return
  7. }
  8. // ToLower converts all characters in the byte slice from A-Z to a-z.
  9. func ToLower(src []byte) []byte {
  10. for i, c := range src {
  11. if c >= 'A' && c <= 'Z' {
  12. src[i] = c + ('a' - 'A')
  13. }
  14. }
  15. return src
  16. }
  17. // EqualFold returns true when s matches case-insensitively the targetLower (which must be lowercase).
  18. func EqualFold(s, targetLower []byte) bool {
  19. if len(s) != len(targetLower) {
  20. return false
  21. }
  22. for i, c := range targetLower {
  23. if s[i] != c && (c < 'A' && c > 'Z' || s[i]+('a'-'A') != c) {
  24. return false
  25. }
  26. }
  27. return true
  28. }
  29. var whitespaceTable = [256]bool{
  30. // ASCII
  31. false, false, false, false, false, false, false, false,
  32. false, true, true, false, true, true, false, false, // tab, new line, form feed, carriage return
  33. false, false, false, false, false, false, false, false,
  34. false, false, false, false, false, false, false, false,
  35. true, false, false, false, false, false, false, false, // space
  36. false, false, false, false, false, false, false, false,
  37. false, false, false, false, false, false, false, false,
  38. false, false, false, false, false, false, false, false,
  39. false, false, false, false, false, false, false, false,
  40. false, false, false, false, false, false, false, false,
  41. false, false, false, false, false, false, false, false,
  42. false, false, false, false, false, false, false, false,
  43. false, false, false, false, false, false, false, false,
  44. false, false, false, false, false, false, false, false,
  45. false, false, false, false, false, false, false, false,
  46. false, false, false, false, false, false, false, false,
  47. // non-ASCII
  48. false, false, false, false, false, false, false, false,
  49. false, false, false, false, false, false, false, false,
  50. false, false, false, false, false, false, false, false,
  51. false, false, false, false, false, false, false, false,
  52. false, false, false, false, false, false, false, false,
  53. false, false, false, false, false, false, false, false,
  54. false, false, false, false, false, false, false, false,
  55. false, false, false, false, false, false, false, false,
  56. false, false, false, false, false, false, false, false,
  57. false, false, false, false, false, false, false, false,
  58. false, false, false, false, false, false, false, false,
  59. false, false, false, false, false, false, false, false,
  60. false, false, false, false, false, false, false, false,
  61. false, false, false, false, false, false, false, false,
  62. false, false, false, false, false, false, false, false,
  63. false, false, false, false, false, false, false, false,
  64. }
  65. // IsWhitespace returns true for space, \n, \r, \t, \f.
  66. func IsWhitespace(c byte) bool {
  67. return whitespaceTable[c]
  68. }
  69. var newlineTable = [256]bool{
  70. // ASCII
  71. false, false, false, false, false, false, false, false,
  72. false, false, true, false, false, true, false, false, // new line, carriage return
  73. false, false, false, false, false, false, false, false,
  74. false, false, false, false, false, false, false, false,
  75. false, false, false, false, false, false, false, false,
  76. false, false, false, false, false, false, false, false,
  77. false, false, false, false, false, false, false, false,
  78. false, false, false, false, false, false, false, false,
  79. false, false, false, false, false, false, false, false,
  80. false, false, false, false, false, false, false, false,
  81. false, false, false, false, false, false, false, false,
  82. false, false, false, false, false, false, false, false,
  83. false, false, false, false, false, false, false, false,
  84. false, false, false, false, false, false, false, false,
  85. false, false, false, false, false, false, false, false,
  86. false, false, false, false, false, false, false, false,
  87. // non-ASCII
  88. false, false, false, false, false, false, false, false,
  89. false, false, false, false, false, false, false, false,
  90. false, false, false, false, false, false, false, false,
  91. false, false, false, false, false, false, false, false,
  92. false, false, false, false, false, false, false, false,
  93. false, false, false, false, false, false, false, false,
  94. false, false, false, false, false, false, false, false,
  95. false, false, false, false, false, false, false, false,
  96. false, false, false, false, false, false, false, false,
  97. false, false, false, false, false, false, false, false,
  98. false, false, false, false, false, false, false, false,
  99. false, false, false, false, false, false, false, false,
  100. false, false, false, false, false, false, false, false,
  101. false, false, false, false, false, false, false, false,
  102. false, false, false, false, false, false, false, false,
  103. false, false, false, false, false, false, false, false,
  104. }
  105. // IsNewline returns true for \n, \r.
  106. func IsNewline(c byte) bool {
  107. return newlineTable[c]
  108. }
  109. // IsAllWhitespace returns true when the entire byte slice consists of space, \n, \r, \t, \f.
  110. func IsAllWhitespace(b []byte) bool {
  111. for _, c := range b {
  112. if !IsWhitespace(c) {
  113. return false
  114. }
  115. }
  116. return true
  117. }
  118. // TrimWhitespace removes any leading and trailing whitespace characters.
  119. func TrimWhitespace(b []byte) []byte {
  120. n := len(b)
  121. start := n
  122. for i := 0; i < n; i++ {
  123. if !IsWhitespace(b[i]) {
  124. start = i
  125. break
  126. }
  127. }
  128. end := n
  129. for i := n - 1; i >= start; i-- {
  130. if !IsWhitespace(b[i]) {
  131. end = i + 1
  132. break
  133. }
  134. }
  135. return b[start:end]
  136. }
  137. // ReplaceMultipleWhitespace replaces character series of space, \n, \t, \f, \r into a single space or newline (when the serie contained a \n or \r).
  138. func ReplaceMultipleWhitespace(b []byte) []byte {
  139. j := 0
  140. prevWS := false
  141. hasNewline := false
  142. for i, c := range b {
  143. if IsWhitespace(c) {
  144. prevWS = true
  145. if IsNewline(c) {
  146. hasNewline = true
  147. }
  148. } else {
  149. if prevWS {
  150. prevWS = false
  151. if hasNewline {
  152. hasNewline = false
  153. b[j] = '\n'
  154. } else {
  155. b[j] = ' '
  156. }
  157. j++
  158. }
  159. b[j] = b[i]
  160. j++
  161. }
  162. }
  163. if prevWS {
  164. if hasNewline {
  165. b[j] = '\n'
  166. } else {
  167. b[j] = ' '
  168. }
  169. j++
  170. }
  171. return b[:j]
  172. }