127 lines
4.1 KiB
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
|
|
}
|
|
}
|
|
}
|
|
}
|