golang实现多种校验码算法(Luhn/Verhoeff/Damm)和ISBN/EAN/UPC计算器功能的插件库checkdigit
Golang实现多种校验码算法(Luhn/Verhoeff/Damm)和ISBN/EAN/UPC计算器功能的插件库checkdigit
关于
checkdigit是一个用Go语言实现的校验码算法和计算器库。
提供的算法
校验算法
- Luhn算法(用于信用卡号等校验)
- Verhoeff算法
- Damm算法
计算器功能
- ISBN-10
- ISBN-13
- EAN-8
- EAN-13
- JAN-8
- JAN-13
- ITF
- UPC
- SSCC
使用示例
安装
go get github.com/osamingo/checkdigit
Luhn算法示例
package main
import (
"fmt"
"github.com/osamingo/checkdigit"
)
func main() {
// 使用Luhn算法验证信用卡号
luhn := checkdigit.NewLuhn()
// 验证信用卡号是否有效
valid := luhn.Verify("79927398713")
fmt.Println("信用卡号是否有效:", valid) // 输出: true
// 计算校验位
digit, err := luhn.Generate("7992739871")
if err != nil {
fmt.Println("生成校验位出错:", err)
return
}
fmt.Println("计算得到的校验位:", digit) // 输出: 3
}
ISBN-13示例
package main
import (
"fmt"
"github.com/osamingo/checkdigit"
)
func main() {
// 使用ISBN-13计算器
isbn13 := checkdigit.NewISBN13()
// 验证ISBN-13是否有效
valid := isbn13.Verify("9780306406157")
fmt.Println("ISBN-13是否有效:", valid) // 输出: true
// 计算ISBN-13校验位
digit, err := isbn13.Generate("978030640615")
if err != nil {
fmt.Println("生成校验位出错:", err)
return
}
fmt.Println("计算得到的校验位:", digit) // 输出: 7
}
Verhoeff算法示例
package main
import (
"fmt"
"github.com/osamingo/checkdigit"
)
func main() {
// 使用Verhoeff算法
verhoeff := checkdigit.NewVerhoeff()
// 验证数字是否有效
valid := verhoeff.Verify("2363")
fmt.Println("数字是否有效:", valid) // 输出: true
// 计算校验位
digit, err := verhoeff.Generate("236")
if err != nil {
fmt.Println("生成校验位出错:", err)
return
}
fmt.Println("计算得到的校验位:", digit) // 输出: 3
}
EAN-13示例
package main
import (
"fmt"
"github.com/osamingo/checkdigit"
)
func main() {
// 使用EAN-13计算器
ean13 := checkdigit.NewEAN13()
// 验证EAN-13条码是否有效
valid := ean13.Verify("4006381333931")
fmt.Println("EAN-13是否有效:", valid) // 输出: true
// 计算EAN-13校验位
digit, err := ean13.Generate("400638133393")
if err != nil {
fmt.Println("生成校验位出错:", err)
return
}
fmt.Println("计算得到的校验位:", digit) // 输出: 1
}
许可证
该项目使用MIT许可证发布。
更多关于golang实现多种校验码算法(Luhn/Verhoeff/Damm)和ISBN/EAN/UPC计算器功能的插件库checkdigit的实战教程也可以访问 https://www.itying.com/category-94-b0.html
1 回复
更多关于golang实现多种校验码算法(Luhn/Verhoeff/Damm)和ISBN/EAN/UPC计算器功能的插件库checkdigit的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html
Golang 校验码算法库实现
下面我将介绍如何使用 Go 语言实现一个包含多种校验码算法的库,支持 Luhn、Verhoeff、Damm 算法以及 ISBN、EAN、UPC 条码的校验计算。
1. 基础实现
首先创建一个 checkdigit
包,包含各种算法的实现:
package checkdigit
// Luhn 算法实现
type Luhn struct{}
func (l Luhn) Generate(seed string) (int, error) {
if seed == "" {
return 0, ErrInvalidArgument
}
sum := 0
alternate := false
for i := len(seed) - 1; i >= 0; i-- {
num := int(seed[i] - '0')
if num < 0 || num > 9 {
return 0, ErrInvalidArgument
}
if alternate {
num *= 2
if num > 9 {
num = (num % 10) + 1
}
}
sum += num
alternate = !alternate
}
return (10 - (sum % 10)) % 10, nil
}
func (l Luhn) Verify(code string) bool {
if len(code) < 2 {
return false
}
seed := code[:len(code)-1]
checkDigit := int(code[len(code)-1] - '0')
digit, err := l.Generate(seed)
if err != nil {
return false
}
return digit == checkDigit
}
// Verhoeff 算法实现
type Verhoeff struct{}
var verhoeffD = [10][10]int{
{0, 1, 2, 3, 4, 5, 6, 7, 8, 9},
{1, 2, 3, 4, 0, 6, 7, 8, 9, 5},
{2, 3, 4, 0, 1, 7, 8, 9, 5, 6},
{3, 4, 0, 1, 2, 8, 9, 5, 6, 7},
{4, 0, 1, 2, 3, 9, 5, 6, 7, 8},
{5, 9, 8, 7, 6, 0, 4, 3, 2, 1},
{6, 5, 9, 8, 7, 1, 0, 4, 3, 2},
{7, 6, 5, 9, 8, 2, 1, 0, 4, 3},
{8, 7, 6, 5, 9, 3, 2, 1, 0, 4},
{9, 8, 7, 6, 5, 4, 3, 2, 1, 0},
}
var verhoeffP = [8][10]int{
{0, 1, 2, 3, 4, 5, 6, 7, 8, 9},
{1, 5, 7, 6, 2, 8, 3, 0, 9, 4},
{5, 8, 0, 3, 7, 9, 6, 1, 4, 2},
{8, 9, 1, 6, 0, 4, 3, 5, 2, 7},
{9, 4, 5, 3, 1, 2, 6, 8, 7, 0},
{4, 2, 8, 6, 5, 7, 3, 9, 0, 1},
{2, 7, 9, 3, 8, 0, 6, 4, 1, 5},
{7, 0, 4, 6, 9, 1, 3, 2, 5, 8},
}
func (v Verhoeff) Generate(seed string) (int, error) {
if seed == "" {
return 0, ErrInvalidArgument
}
c := 0
for i, n := 0, len(seed); i < n; i++ {
num := int(seed[n-1-i] - '0')
if num < 0 || num > 9 {
return 0, ErrInvalidArgument
}
c = verhoeffD[c][verhoeffP[i%8][num]]
}
return verhoeffInv[c], nil
}
func (v Verhoeff) Verify(code string) bool {
if len(code) < 2 {
return false
}
seed := code[:len(code)-1]
checkDigit := int(code[len(code)-1] - '0')
digit, err := v.Generate(seed)
if err != nil {
return false
}
return digit == checkDigit
}
// Damm 算法实现
type Damm struct{}
var dammTable = [10][10]int{
{0, 3, 1, 7, 5, 9, 8, 6, 4, 2},
{7, 0, 9, 2, 1, 5, 4, 8, 6, 3},
{4, 2, 0, 6, 8, 7, 1, 3, 5, 9},
{1, 7, 5, 0, 9, 8, 3, 4, 2, 6},
{6, 1, 2, 3, 0, 4, 5, 9, 7, 8},
{3, 6, 7, 4, 2, 0, 9, 5, 8, 1},
{5, 8, 6, 9, 7, 2, 0, 1, 3, 4},
{8, 9, 4, 5, 3, 6, 2, 0, 1, 7},
{9, 4, 3, 8, 6, 1, 7, 2, 0, 5},
{2, 5, 8, 1, 4, 3, 6, 7, 9, 0},
}
func (d Damm) Generate(seed string) (int, error) {
if seed == "" {
return 0, ErrInvalidArgument
}
interim := 0
for _, c := range seed {
num := int(c - '0')
if num < 0 || num > 9 {
return 0, ErrInvalidArgument
}
interim = dammTable[interim][num]
}
return interim, nil
}
func (d Damm) Verify(code string) bool {
if len(code) < 2 {
return false
}
digit, err := d.Generate(code)
if err != nil {
return false
}
return digit == 0
}
2. ISBN/EAN/UPC 实现
// ISBN 校验
type ISBN struct{}
func (i ISBN) Generate(seed string) (int, error) {
if len(seed) != 12 && len(seed) != 9 {
return 0, ErrInvalidArgument
}
sum := 0
weight := 10
for _, c := range seed {
num := int(c - '0')
if num < 0 || num > 9 {
return 0, ErrInvalidArgument
}
sum += num * weight
weight--
}
remainder := sum % 11
checkDigit := 11 - remainder
if checkDigit == 10 {
return 'X', nil
}
if checkDigit == 11 {
checkDigit = 0
}
return checkDigit, nil
}
func (i ISBN) Verify(code string) bool {
if len(code) != 10 && len(code) != 13 {
return false
}
seed := code[:len(code)-1]
lastChar := code[len(code)-1]
var checkDigit int
if lastChar == 'X' || lastChar == 'x' {
checkDigit = 10
} else {
checkDigit = int(lastChar - '0')
}
digit, err := i.Generate(seed)
if err != nil {
return false
}
return digit == checkDigit
}
// EAN/UPC 校验
type EAN struct{}
func (e EAN) Generate(seed string) (int, error) {
if len(seed) != 7 && len(seed) != 11 && len(seed) != 12 {
return 0, ErrInvalidArgument
}
sum := 0
for i, c := range seed {
num := int(c - '0')
if num < 0 || num > 9 {
return 0, ErrInvalidArgument
}
if (len(seed)-i)%2 == 1 {
sum += num * 3
} else {
sum += num
}
}
remainder := sum % 10
if remainder == 0 {
return 0, nil
}
return 10 - remainder, nil
}
func (e EAN) Verify(code string) bool {
length := len(code)
if length != 8 && length != 12 && length != 13 {
return false
}
seed := code[:length-1]
checkDigit := int(code[length-1] - '0')
digit, err := e.Generate(seed)
if err != nil {
return false
}
return digit == checkDigit
}
3. 使用示例
package main
import (
"fmt"
"github.com/yourusername/checkdigit"
)
func main() {
// Luhn 算法示例
luhn := checkdigit.Luhn{}
luhnCheck, _ := luhn.Generate("7992739871")
fmt.Printf("Luhn check digit: %d\n", luhnCheck) // 输出: 3
fmt.Println("Luhn verify:", luhn.Verify("79927398713")) // true
// Verhoeff 算法示例
verhoeff := checkdigit.Verhoeff{}
verhoeffCheck, _ := verhoeff.Generate("236")
fmt.Printf("Verhoeff check digit: %d\n", verhoeffCheck) // 输出: 3
fmt.Println("Verhoeff verify:", verhoeff.Verify("2363")) // true
// ISBN 示例
isbn := checkdigit.ISBN{}
isbnCheck, _ := isbn.Generate("030640615")
fmt.Printf("ISBN check digit: %d\n", isbnCheck) // 输出: 2 (ISBN: 0-306-40615-2)
fmt.Println("ISBN verify:", isbn.Verify("0306406152")) // true
// EAN-13 示例
ean := checkdigit.EAN{}
eanCheck, _ := ean.Generate("40063813339")
fmt.Printf("EAN check digit: %d\n", eanCheck) // 输出: 1 (EAN: 400638133391)
fmt.Println("EAN verify:", ean.Verify("400638133391")) // true
}
4. 扩展功能
可以添加更多实用功能:
// 自动检测并验证不同类型
func AutoVerify(code string) bool {
switch len(code) {
case 8:
return EAN{}.Verify(code)
case 10:
return ISBN{}.Verify(code)
case 12:
return EAN{}.Verify(code)
case 13:
if code[0:3] == "978" || code[0:3] == "979" {
return ISBN{}.Verify(code)
}
return EAN{}.Verify(code)
default:
return false
}
}
// 计算多种校验码
func CalculateAll(seed string) map[string]int {
result := make(map[string]int)
if l, err := Luhn{}.Generate(seed); err == nil {
result["luhn"] = l
}
if v, err := Verhoeff{}.Generate(seed); err == nil {
result["verhoeff"] = v
}
if d, err := Damm{}.Generate(seed); err == nil {
result["damm"] = d
}
return result
}
这个库提供了多种校验算法的实现,可以用于验证信用卡号、身份证号、商品条码等各种需要校验码的场景。每种算法都实现了相同的接口,方便统一调用。