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') }