82 lines
1.4 KiB
Go
82 lines
1.4 KiB
Go
|
package parser
|
||
|
|
||
|
import (
|
||
|
"strings"
|
||
|
"unicode"
|
||
|
)
|
||
|
|
||
|
func ISBN(orig string) string {
|
||
|
isbn := getISBN(orig)
|
||
|
|
||
|
if len(isbn) != 13 && len(isbn) != 10 {
|
||
|
return ""
|
||
|
}
|
||
|
if !validChecksum(isbn) {
|
||
|
return ""
|
||
|
}
|
||
|
|
||
|
return toISBN13(isbn)
|
||
|
}
|
||
|
|
||
|
func getISBN(src string) string {
|
||
|
isbn := strings.ToUpper(src)
|
||
|
isNotNumber := func(r rune) bool {
|
||
|
return !unicode.IsNumber(r)
|
||
|
}
|
||
|
isNotNumberOrX := func(r rune) bool {
|
||
|
return !unicode.IsNumber(r) && r != 'X'
|
||
|
}
|
||
|
|
||
|
isbn = strings.TrimLeftFunc(isbn, isNotNumber)
|
||
|
isbn = strings.TrimRightFunc(isbn, isNotNumberOrX)
|
||
|
isbn = strings.Replace(isbn, "-", "", -1)
|
||
|
isbn = strings.Replace(isbn, " ", "", -1)
|
||
|
|
||
|
if len(isbn) > 13 {
|
||
|
isbn = isbn[:13]
|
||
|
}
|
||
|
return isbn
|
||
|
}
|
||
|
|
||
|
func validChecksum(isbn string) bool {
|
||
|
if len(isbn) == 10 {
|
||
|
return rune(isbn[9]) == checkDigit10(isbn)
|
||
|
}
|
||
|
return rune(isbn[12]) == checkDigit13(isbn)
|
||
|
}
|
||
|
|
||
|
func toISBN13(isbn string) string {
|
||
|
if len(isbn) == 13 {
|
||
|
return isbn
|
||
|
}
|
||
|
|
||
|
isbn = "978" + isbn
|
||
|
return isbn[:12] + string(checkDigit13(isbn))
|
||
|
}
|
||
|
|
||
|
func checkDigit10(isbn string) rune {
|
||
|
acc := 0
|
||
|
for i, r := range isbn[:9] {
|
||
|
acc += (10 - i) * int(r-'0')
|
||
|
}
|
||
|
check := (11 - (acc % 11)) % 11
|
||
|
|
||
|
if check == 10 {
|
||
|
return 'X'
|
||
|
}
|
||
|
return rune(check + '0')
|
||
|
}
|
||
|
|
||
|
func checkDigit13(isbn string) rune {
|
||
|
acc := 0
|
||
|
for i, r := range isbn[:12] {
|
||
|
n := int(r - '0')
|
||
|
if i%2 == 1 {
|
||
|
n = 3 * n
|
||
|
}
|
||
|
acc += n
|
||
|
}
|
||
|
check := (10 - (acc % 10)) % 10
|
||
|
return rune(check + '0')
|
||
|
}
|