k.go 2.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101
  1. package kata
  2. import (
  3. "math"
  4. "strings"
  5. "unicode"
  6. "unicode/utf8"
  7. )
  8. func Chunk(s string, index int) string {
  9. if index < 0 || index > 4 {
  10. return ""
  11. }
  12. var baseSize, size int
  13. if len(s)%5 == 0 {
  14. baseSize = len(s) / 5
  15. size = baseSize
  16. } else {
  17. baseSize = int(math.Ceil(float64(len(s)) / 5))
  18. if index == 4 {
  19. size = len(s) % baseSize
  20. } else {
  21. size = baseSize
  22. }
  23. }
  24. res := s[index*baseSize : index*baseSize+size]
  25. return res
  26. }
  27. /*
  28. Prefix builds the encoding prefix.
  29. It assumes s is a string containing at least one rune, and its first rune is an
  30. ASCII character, upper- or lower-case.
  31. */
  32. func Prefix(s string, shift int) []rune {
  33. r := []rune(s)[0]
  34. r = unicode.ToLower(r)
  35. var off = r - 'a'
  36. if off < 0 || off >= 26 {
  37. panic("Invalid string")
  38. }
  39. off += int32(shift)
  40. off %= 26
  41. r2 := 'a' + off
  42. return []rune{r, r2}
  43. }
  44. func ApplyShift(r rune, shift int) rune {
  45. if r >= 'A' && r <= 'Z' {
  46. return 'A' + (r-'A'+rune(shift))%26
  47. }
  48. if r >= 'a' && r <= 'z' {
  49. return 'a' + (r-'a'+rune(shift))%26
  50. }
  51. return r
  52. }
  53. func Shift(s string) int {
  54. if utf8.RuneCountInString(s) < 2 {
  55. panic("String too short to decode")
  56. }
  57. rs := []rune(s)
  58. var initial, shifted int = int(rs[0]), int(rs[1])
  59. shift := (26 + shifted - initial)%26 // Avoid negatives
  60. return shift
  61. }
  62. func Encode(s string, shift int) []string {
  63. const prefixLen = 2
  64. src := []rune(s)
  65. dst := make([]rune, len(src)+prefixLen)
  66. prefix := Prefix(s, shift)
  67. n := copy(dst, prefix)
  68. if n != prefixLen {
  69. panic("copy error on prefix")
  70. }
  71. for i, r := range src {
  72. dst[i+prefixLen] = ApplyShift(r, shift)
  73. }
  74. s = string(dst)
  75. res := []string{Chunk(s, 0), Chunk(s, 1), Chunk(s, 2), Chunk(s, 3), Chunk(s, 4)}
  76. if len(res[4]) == 0 {
  77. res = res[:4]
  78. }
  79. return res
  80. }
  81. func Decode(arr []string) string {
  82. reverseShift := 26 - Shift(arr[0])
  83. s := strings.Join(arr, "")[2:]
  84. l := utf8.RuneCountInString(s)
  85. runes := make([]rune, l)
  86. for i, r := range s {
  87. runes[i] = ApplyShift(r, reverseShift)
  88. }
  89. s = string(runes)
  90. return s
  91. }