ascii.go 1.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263
  1. package misspell
  2. // ByteToUpper converts an ascii byte to upper cases
  3. // Uses a branchless algorithm
  4. func ByteToUpper(x byte) byte {
  5. b := byte(0x80) | x
  6. c := b - byte(0x61)
  7. d := ^(b - byte(0x7b))
  8. e := (c & d) & (^x & 0x7f)
  9. return x - (e >> 2)
  10. }
  11. // ByteToLower converts an ascii byte to lower case
  12. // uses a branchless algorithm
  13. func ByteToLower(eax byte) byte {
  14. ebx := eax&byte(0x7f) + byte(0x25)
  15. ebx = ebx&byte(0x7f) + byte(0x1a)
  16. ebx = ((ebx & ^eax) >> 2) & byte(0x20)
  17. return eax + ebx
  18. }
  19. // ByteEqualFold does ascii compare, case insensitive
  20. func ByteEqualFold(a, b byte) bool {
  21. return a == b || ByteToLower(a) == ByteToLower(b)
  22. }
  23. // StringEqualFold ASCII case-insensitive comparison
  24. // golang toUpper/toLower for both bytes and strings
  25. // appears to be Unicode based which is super slow
  26. // based from https://codereview.appspot.com/5180044/patch/14007/21002
  27. func StringEqualFold(s1, s2 string) bool {
  28. if len(s1) != len(s2) {
  29. return false
  30. }
  31. for i := 0; i < len(s1); i++ {
  32. c1 := s1[i]
  33. c2 := s2[i]
  34. // c1 & c2
  35. if c1 != c2 {
  36. c1 |= 'a' - 'A'
  37. c2 |= 'a' - 'A'
  38. if c1 != c2 || c1 < 'a' || c1 > 'z' {
  39. return false
  40. }
  41. }
  42. }
  43. return true
  44. }
  45. // StringHasPrefixFold is similar to strings.HasPrefix but comparison
  46. // is done ignoring ASCII case.
  47. // /
  48. func StringHasPrefixFold(s1, s2 string) bool {
  49. // prefix is bigger than input --> false
  50. if len(s1) < len(s2) {
  51. return false
  52. }
  53. if len(s1) == len(s2) {
  54. return StringEqualFold(s1, s2)
  55. }
  56. return StringEqualFold(s1[:len(s2)], s2)
  57. }