RosettaCodeData/Task/UPC/Go/upc.go

127 lines
4.1 KiB
Go

package main
import (
"fmt"
"regexp"
)
var bits = []string{
"0 0 0 1 1 0 1 ",
"0 0 1 1 0 0 1 ",
"0 0 1 0 0 1 1 ",
"0 1 1 1 1 0 1 ",
"0 1 0 0 0 1 1 ",
"0 1 1 0 0 0 1 ",
"0 1 0 1 1 1 1 ",
"0 1 1 1 0 1 1 ",
"0 1 1 0 1 1 1 ",
"0 0 0 1 0 1 1 ",
}
var (
lhs = make(map[string]int)
rhs = make(map[string]int)
)
var weights = []int{3, 1, 3, 1, 3, 1, 3, 1, 3, 1, 3, 1}
const (
s = "# #"
m = " # # "
e = "# #"
d = "(?:#| ){7}"
)
func init() {
for i := 0; i <= 9; i++ {
lt := make([]byte, 7)
rt := make([]byte, 7)
for j := 0; j < 14; j += 2 {
if bits[i][j] == '1' {
lt[j/2] = '#'
rt[j/2] = ' '
} else {
lt[j/2] = ' '
rt[j/2] = '#'
}
}
lhs[string(lt)] = i
rhs[string(rt)] = i
}
}
func reverse(s string) string {
b := []byte(s)
for i, j := 0, len(b)-1; i < j; i, j = i+1, j-1 {
b[i], b[j] = b[j], b[i]
}
return string(b)
}
func main() {
barcodes := []string{
" # # # ## # ## # ## ### ## ### ## #### # # # ## ## # # ## ## ### # ## ## ### # # # ",
" # # # ## ## # #### # # ## # ## # ## # # # ### # ### ## ## ### # # ### ### # # # ",
" # # # # # ### # # # # # # # # # # ## # ## # ## # ## # # #### ### ## # # ",
" # # ## ## ## ## # # # # ### # ## ## # # # ## ## # ### ## ## # # #### ## # # # ",
" # # ### ## # ## ## ### ## # ## # # ## # # ### # ## ## # # ### # ## ## # # # ",
" # # # # ## ## # # # # ## ## # # # # # #### # ## # #### #### # # ## # #### # # ",
" # # # ## ## # # ## ## # ### ## ## # # # # # # # # ### # # ### # # # # # ",
" # # # # ## ## # # ## ## ### # # # # # ### ## ## ### ## ### ### ## # ## ### ## # # ",
" # # ### ## ## # # #### # ## # #### # #### # # # # # ### # # ### # # # ### # # # ",
" # # # #### ## # #### # # ## ## ### #### # # # # ### # ### ### # # ### # # # ### # # ",
}
// Regular expression to check validity of a barcode and extract digits. However we accept any number
// of spaces at the beginning or end i.e. we don't enforce a minimum of 9.
expr := fmt.Sprintf(`^\s*%s(%s)(%s)(%s)(%s)(%s)(%s)%s(%s)(%s)(%s)(%s)(%s)(%s)%s\s*$`,
s, d, d, d, d, d, d, m, d, d, d, d, d, d, e)
rx := regexp.MustCompile(expr)
fmt.Println("UPC-A barcodes:")
for i, bc := range barcodes {
for j := 0; j <= 1; j++ {
if !rx.MatchString(bc) {
fmt.Printf("%2d: Invalid format\n", i+1)
break
}
codes := rx.FindStringSubmatch(bc)
digits := make([]int, 12)
var invalid, ok bool // False by default.
for i := 1; i <= 6; i++ {
digits[i-1], ok = lhs[codes[i]]
if !ok {
invalid = true
}
digits[i+5], ok = rhs[codes[i+6]]
if !ok {
invalid = true
}
}
if invalid { // Contains at least one invalid digit.
if j == 0 { // Try reversing.
bc = reverse(bc)
continue
} else {
fmt.Printf("%2d: Invalid digit(s)\n", i+1)
break
}
}
sum := 0
for i, d := range digits {
sum += weights[i] * d
}
if sum%10 != 0 {
fmt.Printf("%2d: Checksum error\n", i+1)
break
} else {
ud := ""
if j == 1 {
ud = "(upside down)"
}
fmt.Printf("%2d: %v %s\n", i+1, digits, ud)
break
}
}
}
}