main.go 3.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199
  1. package inns
  2. // The package implements the basic
  3. // Russian Federation INN format
  4. // storing it in int64 to keep
  5. // searching and storing as
  6. // quick as possible.
  7. import (
  8. "strings"
  9. "unicode"
  10. "strconv"
  11. "fmt"
  12. "slices"
  13. )
  14. type Type uint8
  15. const (
  16. TypeIncorrect Type = iota
  17. TypeLegal
  18. TypeIndividual
  19. )
  20. func removeSpaces(s string) string {
  21. return strings.Map(func(r rune) rune{
  22. if unicode.IsSpace(r) {
  23. return -1
  24. }
  25. return r
  26. }, s)
  27. }
  28. type INN int64
  29. func NewFromInt64(innRaw int64) (INN, error) {
  30. inn := INN(innRaw)
  31. if !inn.isCorrectLen() {
  32. return -1, ErrIncorrectLen
  33. }
  34. if !inn.isSumCorrect() {
  35. return -1, ErrSumsNotMatch
  36. }
  37. return inn, nil
  38. }
  39. func (inn INN) IsCorrect() bool {
  40. _, err := NewFromInt64(int64(inn))
  41. return err == nil
  42. }
  43. // Convert string with spaces into the INN
  44. // and return error if anything is wrong with it.
  45. func NewFromStr(str string) (INN, error) {
  46. str = removeSpaces(str)
  47. innRaw, err := strconv.ParseInt(str, 10, 64)
  48. if err != nil {
  49. return -1, ErrIncorrectFormat
  50. }
  51. return NewFromInt64(innRaw)
  52. }
  53. func (inn INN) Type() Type {
  54. ln := inn.length()
  55. switch ln {
  56. case 9, 10:
  57. return TypeLegal
  58. case 11, 12:
  59. return TypeIndividual
  60. }
  61. return TypeIncorrect
  62. }
  63. func (inn INN) length() int {
  64. ln := 0
  65. for {
  66. if inn == 0 {
  67. break
  68. }
  69. inn /= 10
  70. ln++
  71. }
  72. if ln == 9 || ln == 11 {
  73. ln++
  74. }
  75. return ln
  76. }
  77. func (inn INN) isCorrectLen() bool {
  78. ln := inn.length()
  79. if ln == 9 || ln == 11 {
  80. ln++
  81. }
  82. return ln == 10 || ln == 12
  83. }
  84. var (
  85. // Koefs for the control sum.
  86. innSum10 = [9]int64{
  87. 2, 4, 10, 3, 5, 9, 4, 6, 8,
  88. }
  89. innSum11 = [10]int64{
  90. 7, 2, 4, 10, 3, 5, 9, 4, 6, 8,
  91. }
  92. innSum12 = [11]int64{
  93. 3, 7, 2, 4, 10, 3, 5, 9, 4, 6, 8,
  94. }
  95. )
  96. // Get the integer representation of digits in string INN.
  97. func (inn INN) digits() []int64 {
  98. ln := inn.length()
  99. v := int64(inn)
  100. ret := make([]int64, ln)
  101. for i := 0 ; i<ln ; i++{
  102. ret[i] = v % 10
  103. v /= 10
  104. }
  105. slices.Reverse(ret)
  106. return ret
  107. }
  108. //
  109. func (inn INN) specifiedSum() int64 {
  110. ln := inn.length()
  111. v := int64(inn)
  112. switch ln {
  113. case 10:
  114. return v%10
  115. case 12:
  116. return v%100
  117. default:
  118. return -1
  119. }
  120. }
  121. // Returns the supposed control sum rune. (the last number)
  122. func (inn INN) sum() int64 {
  123. d := inn.digits()
  124. ln := inn.length()
  125. switch ln {
  126. case 10 :
  127. var n10 int64
  128. for i, ni := range d[:9] {
  129. n10 += innSum10[i] * ni
  130. }
  131. n10 = (n10 % 11) % 10
  132. return n10
  133. case 12 :
  134. var n11 int64
  135. for i, ni := range d[:10] {
  136. n11 += innSum11[i] * ni
  137. }
  138. n11 = (n11 % 11) % 10
  139. var n12 int64
  140. for i, ni := range d[:10] {
  141. n12 += innSum12[i] * ni
  142. }
  143. n12 += innSum12[10] * n11
  144. n12 = (n12 % 11) % 10
  145. return n11*10 + n12
  146. }
  147. return -1
  148. }
  149. func (inn INN) isSumCorrect() bool {
  150. return inn.specifiedSum() == inn.sum()
  151. }
  152. func (inn INN) String() string {
  153. return fmt.Sprintf("%d", inn)
  154. }
  155. // Fancy way to print INN with space delimiters.
  156. func (inn INN) Fancy() string {
  157. ln := inn.length()
  158. str := fmt.Sprintf("%d", inn)
  159. // Adding zero depending on length.
  160. if len(str) == 9 || len(str) == 11 {
  161. str = "0"+str
  162. }
  163. switch ln {
  164. case 10 :
  165. return fmt.Sprintf("%s %s %s", str[:4], str[4:9], str[9:])
  166. case 12 :
  167. return fmt.Sprintf("%s %s %s", str[:4], str[4:10], str[10:])
  168. }
  169. // Reaching the point if the length is incorrect.
  170. return "<"+ErrIncorrectLen.Error()+">"
  171. }