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
}

这个库提供了多种校验算法的实现,可以用于验证信用卡号、身份证号、商品条码等各种需要校验码的场景。每种算法都实现了相同的接口,方便统一调用。

回到顶部