Added Damm algorithm
This commit is contained in:
parent
b0fba45d68
commit
878cb24695
6 changed files with 132 additions and 10 deletions
53
README.md
53
README.md
|
@ -11,13 +11,16 @@ Pure Go implementations.
|
|||
### Usage
|
||||
|
||||
```golang
|
||||
import "github.com/neonxp/checksum/luhn"
|
||||
import (
|
||||
"github.com/neonxp/checksum"
|
||||
"github.com/neonxp/checksum/luhn"
|
||||
)
|
||||
...
|
||||
err := luhn.Check("4561261212345467")
|
||||
switch err {
|
||||
case luhn.ErrInvalidNumber:
|
||||
case checksum.ErrInvalidNumber:
|
||||
// Not a number
|
||||
case luhn.ErrInvalidChecksum:
|
||||
case checksum.ErrInvalidChecksum:
|
||||
// Invalid checksum
|
||||
case nil:
|
||||
// Valid number
|
||||
|
@ -33,14 +36,17 @@ switch err {
|
|||
### Usage
|
||||
|
||||
```golang
|
||||
import "github.com/neonxp/checksum/verhoeff"
|
||||
import (
|
||||
"github.com/neonxp/checksum"
|
||||
"github.com/neonxp/checksum/verhoeff"
|
||||
)
|
||||
...
|
||||
numberWithoutChecksum := "4561261212345467"
|
||||
err := verhoeff.Check(number)
|
||||
switch err {
|
||||
case luhn.ErrInvalidNumber:
|
||||
case checksum.ErrInvalidNumber:
|
||||
// Not a number
|
||||
case luhn.ErrInvalidChecksum:
|
||||
case checksum.ErrInvalidChecksum:
|
||||
// Invalid checksum
|
||||
case nil:
|
||||
// Valid number
|
||||
|
@ -55,3 +61,38 @@ if err := verhoeff.Check(numberWithChecksum); err != nil {
|
|||
panic(err)
|
||||
}
|
||||
```
|
||||
|
||||
# Damm algorithm
|
||||
|
||||
> In error detection, the Damm algorithm is a check digit algorithm that detects all single-digit errors and all adjacent transposition errors. It was presented by H. Michael Damm in 2004.
|
||||
|
||||
[Wikipedia](https://en.wikipedia.org/wiki/Damm_algorithm)
|
||||
|
||||
### Usage
|
||||
|
||||
```golang
|
||||
import (
|
||||
"github.com/neonxp/checksum"
|
||||
"github.com/neonxp/checksum/damm"
|
||||
)
|
||||
...
|
||||
numberWithoutChecksum := "4561261212345467"
|
||||
err := damm.Check(number)
|
||||
switch err {
|
||||
case checksum.ErrInvalidNumber:
|
||||
// Not a number
|
||||
case checksum.ErrInvalidChecksum:
|
||||
// Invalid checksum
|
||||
case nil:
|
||||
// Valid number
|
||||
}
|
||||
|
||||
checksum, err := damm.Generate(numberWithoutChecksum)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
numberWithChecksum := numberWithoutChecksum + checksum
|
||||
if err := damm.Check(numberWithChecksum); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
```
|
||||
|
|
49
damm/damm.go
Normal file
49
damm/damm.go
Normal file
|
@ -0,0 +1,49 @@
|
|||
package damm
|
||||
|
||||
import (
|
||||
"strconv"
|
||||
|
||||
"github.com/neonxp/checksum"
|
||||
)
|
||||
|
||||
var d = [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},
|
||||
}
|
||||
|
||||
// Check number is correct by damm algorithm
|
||||
func Check(number string) error {
|
||||
c := 0
|
||||
for _, ch := range number {
|
||||
num, err := strconv.Atoi(string(ch))
|
||||
if err != nil {
|
||||
return checksum.ErrInvalidNumber
|
||||
}
|
||||
c = d[c][num]
|
||||
}
|
||||
if c != 0 {
|
||||
return checksum.ErrInvalidChecksum
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// Generate checksum (must be added to number at right)
|
||||
func Generate(number string) (string, error) {
|
||||
c := 0
|
||||
for _, ch := range number {
|
||||
num, err := strconv.Atoi(string(ch))
|
||||
if err != nil {
|
||||
return "", checksum.ErrInvalidNumber
|
||||
}
|
||||
c = d[c][num]
|
||||
}
|
||||
return strconv.Itoa(c), nil
|
||||
}
|
32
damm/damm_test.go
Normal file
32
damm/damm_test.go
Normal file
|
@ -0,0 +1,32 @@
|
|||
package damm
|
||||
|
||||
import (
|
||||
"log"
|
||||
"testing"
|
||||
|
||||
"github.com/neonxp/checksum"
|
||||
)
|
||||
|
||||
func TestLuhn(t *testing.T) {
|
||||
samples := map[string]error{
|
||||
"456126121234546": checksum.ErrInvalidChecksum,
|
||||
"A56126121234546": checksum.ErrInvalidNumber,
|
||||
"5724": nil,
|
||||
}
|
||||
for num, result := range samples {
|
||||
if err := Check(num); err != result {
|
||||
t.Errorf("Expected %+v actual %+v for %s", result, err, num)
|
||||
}
|
||||
}
|
||||
|
||||
num := "572"
|
||||
checksum, err := Generate(num)
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
numberWithChecksum := num + checksum
|
||||
log.Println(numberWithChecksum)
|
||||
if err := Check(numberWithChecksum); err != nil {
|
||||
t.Errorf("Expected no error actual %+v for %s", err, numberWithChecksum)
|
||||
}
|
||||
}
|
|
@ -14,7 +14,7 @@ func TestLuhn(t *testing.T) {
|
|||
}
|
||||
for num, result := range samples {
|
||||
if err := Check(num); err != result {
|
||||
t.Errorf("Expected %+v actual %+v", result, err)
|
||||
t.Errorf("Expected %+v actual %+v for %s", result, err, num)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -33,7 +33,7 @@ var p = [8][10]int{
|
|||
|
||||
var inv = [10]int{0, 4, 3, 2, 1, 5, 6, 7, 8, 9}
|
||||
|
||||
// Check number is correct by luhn algorithm
|
||||
// Check number is correct by verhoeff algorithm
|
||||
func Check(number string) error {
|
||||
c := 0
|
||||
numbers := strings.Split(number, "")
|
||||
|
|
|
@ -18,7 +18,7 @@ func TestVerhoeff(t *testing.T) {
|
|||
}
|
||||
for num, result := range samples {
|
||||
if err := Check(num); err != result {
|
||||
t.Errorf("Expected %+v actual %+v", result, err)
|
||||
t.Errorf("Expected %+v actual %+v for %s", result, err, num)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -29,6 +29,6 @@ func TestVerhoeff(t *testing.T) {
|
|||
}
|
||||
numberWithChecksum := num + checksum
|
||||
if err := Check(numberWithChecksum); err != nil {
|
||||
t.Errorf("Expected no error actual %+v", err)
|
||||
t.Errorf("Expected no error actual %+v for %s", err, numberWithChecksum)
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue