Montag, 15. März 2010

Flexible Prüfziffernberechnung mit Modulo und Gewichtung / Flexible check digit calculation with modulo and weighting

Prüfziffernberechnungen gibt es wie Sand am Meer. Speziell im Bereich Barcoding sind sie in den verschiedensten Varianten vorzufinden. Egal ob Code 2aus5il, Code128 oder EAN128. Sie alle verfügen über Prüfziffern.

Die Unterschiede liegen bei fast allen diesen Varianten bei der Wertigkeit der Multiplikatoren und dem Modulowert. Beginnt bei einem EAN-13 die Multiplikation mit 1 und wechselt sich danach mit 3 ab so arbeitet die Berechnung für EAN-14 genau umgekehrt. Beim EAN-128 hingegen liegt der Unterschied zum EAN-13 im Modulowert. Anstelle von 10 wird hier mit 103 gearbeitet. Die Berechnung des Code128 wiederum beruht auf den selben Multiplikatoren wie beim EAN128, arbeitet jedoch wie der EAN13 mit einem Modulowort von 10.

Am Beispiel einer Code128 Nummer sähe die Berechnung wie folgt aus:    
EAN-Nummer        8 154711 00011                                        
Ziffern           8  1  5  4  7  1  1  0  0  0  1  1                    
Multiplikation    3  1  3  1  3  1  3  1  3  1  3  1                    
Ergebnis          24 1  15 4  21 1  3  0  0  0  3  1 Summe: 73        
Division durch 10 ergibt einen Restwert von 3                        
Subtrahiert von 10 erhalten wir als Prüfziffer die 7                

Um nun mit verschiedenen Multiplikatoren und Modulowerten arbeiten zu können benötigen wir zwei Funktionen. Die Erste beinhaltet die eigentliche Berechnung welche wiederum als erstes die zweite Funktion aufruft, in welcher die Wertezuweisung für die Multiplikatoren und den Modulowert vorgenommen werden.

Diese zweite Funktion kann natürlich anstatt als fixe Funktion auch als Cursor, basierend auf einer XML Datei oder einer Tabelle, verfügbar gemacht werden.

* // Funktionstest
CLEAR
?GetCheckDigit([815471100011],[EAN-13])
?GetCheckDigit([815471100012],[EAN-14])
?GetCheckDigit([815471100013],[Code25])
?GetCheckDigit([815471100014],[Code128])
?GetCheckDigit([815471100015],[Leitcode])

FUNCTION GetCheckDigit as String
LPARAMETERS pcString as String, pcVariante as String

    LOCAL    lcReturn as String, i as Integer, liQuersumme as Integer, ;
            liMP1 as Integer, liMP2 as Integer, liModulo as Integer
    STORE [] TO lcReturn
    STORE 0 TO liQuersumme, liMP1, liMP2, liModulo
    
    IF GetCheckDigitValues(pcVariante,@liMP1,@liMP2,@liModulo)

        FOR i = 1 TO LEN(pcString)
            * // Bei ungeraden Position mit liMP1 multiplizieren, andern-    
            * // falls nur mit liMP2 (=Beibehaltung des Originalwertes)      
            liQuersumme = liQuersumme + (INT(VAL(SUBSTR(pcString,i,1)) * IIF(MOD(i,2) > 0,liMP1,liMP2)))
        ENDFOR 

        * // Die berechnete Quersumme nun mit Modulo auf den         
        * // Restwert reduzieren                                    
        lcReturn = CAST(IIF(10 - MOD(liQuersumme, liModulo) = liModulo,0,liModulo - MOD(liQuersumme, liModulo)) as C(1))
    ENDIF  
    
    RETURN lcReturn
    
ENDFUNC 

FUNCTION GetCheckDigitValues as Boolean
LPARAMETERS pcVariante as String, riMP1 as Integer, riMP2 as Integer, riModulo as Integer
    LOCAL llReturn as Boolean
    lLReturn = .T.
    pcVariante = UPPER(pcVariante)
    DO CASE 
    CASE pcVariante = [EAN-13]
        riMP1        = 1
        riMP2        = 3
        riModulo    = 10
    CASE INLIST(pcVariante,[CODE25],[CODE128],[EAN-14],[ITF-14],[SCC-14],[DUN-14])
        riMP1        = 3
        riMP2        = 1
        riModulo    = 10
    CASE INLIST(pcVariante,[EAN-128],[GS1-128],[UCC-128])
        riMP1        = 1
        riMP2        = 3
        riModulo    = 103
    CASE pcVariante = [LEITCODE]
        riMP1        = 4
        riMP2        = 9
        riModulo    = 10
    OTHERWISE 
        llReturn = .F.
    ENDCASE 
    RETURN llReturn 
ENDFUNC 

Kommentare:

  1. Das erste Beispiel ist m.M. nach ne EAN13, nicht ne EAN128 Berechnung?

    AntwortenLöschen
  2. Hallo wOOdy,

    das Musterbeispiel im ersten grauen Block ist ein Code128. Erster Multiplikator: 3, zweiter Multiplikator: 1, Modulowert: 10

    Der Unterschied zum EAN13 ist allerdings tatsächlich winzig. Beim EAN13 sind die beiden Multiplikatoren in ihrer Reihenfolge ausgetauscht.

    Vermutlich kommt Deine Irritation daher, dass im vorstehenden Einleitungstext nur die Rede von EAN13 und EAN128 ist. Das werde ich sicherheitshalber mal korrigieren. :-)

    AntwortenLöschen