Java: Luhn Algorithmus implementieren?

2 Antworten

Vom Fragesteller als hilfreich ausgezeichnet

Deine Variante (?), also das erste Bild, wird so nicht funktionieren.

Es scheitert bereits in Zeile 7, da der Typ long keine Methode length hat. Es empiehlt sich ein Typ, worüber man iterieren kann. Das wäre ein String oder ein Array/Liste.

Dazu gibst du immer true zurück. Der eigentliche Wert ist bei dir egal.

Ich wirklich schöne Implementation für dein Problem mit deiner erforderlichen Signatur konnte ich nicht finden.

Meine Möglichkeit auf Basis des dritten Bildes (aka. Wikipedia Beispiel):

boolean luhnTest(long z) {
    // Umwandlung in ein String, damit der Zugriff auf jede Ziffer möglich ist
    final String numberString = Long.toString(z);
    // Umwandlung in Char Array, damit das Iterieren möglich ist
    final char[] numberCharArray =numberString.toCharArray();

    final int digitCount = numberCharArray.length;
    int checkSum = 0;

    for (int i = 0; i < digitCount; i++) {
        // Char von der aktuellen Iteration finden
        final char digitChar = numberCharArray[digitCount - i - 1];
        // Umwandlung in ein String, da der Typ Char im Anschluss nicht akzeptiert wird
        final String digitString = String.valueOf(digitChar);
        // Umwandlung in ein Zahlen Typ, damit Berechnungen möglich sind
        int digit = Integer.parseInt(digitString);

        if (i % 2 == 1) {
            digit *= 2;
        }

        checkSum += digit > 9 ? digit - 9 : digit;
    }

    return checkSum % 10 == 0;
}

Da als Parameter undebingt ein long erwünscht wird, ist einiges an Umwandlung von Datentypen nötig. Die Übergabe von einem String oder sogar int Array würde bei der Funktion mehr Sinn ergeben.

In dem Fall würde sich vermutlich die Extraktion der Ziffern durch den Modulo Operator besser anbieten.

Das würde dann so aussehen:

boolean luhnTest(long z) {
    int checkSum = 0;
    int i = 0;

    while (z > 0) {
        long digit = z % 10;
        z /= 10;

        if (i % 2 == 1) {
            digit *= 2;
        }
        i++;
        checkSum += digit > 9 ? digit - 9 : digit;
    }
    return checkSum % 10 == 0;
}

Eine Erklärung, wie die Ziffer gefunden wird.

Variante 1 mit dem String sollte selbsterklärender sein, wenn die Umwandlung der Typen nicht nötig wäre.

Variante 2 sieht in diesem Fall übersichtlicher aus. Wie die Ziffer herausgefunden wird, ist vielleicht nicht jeden auf dem ersten Blick geläufig.

verreisterNutzer  08.02.2022, 19:59

Wenn ich eine echte IMEI Nummer eingebe steht fehlerhafte eingabe

0
tide1109  08.02.2022, 20:26
@verreisterNutzer

Habe es einmal bei mir getestet. Habe eine Kreditkartennummer und zwei IMEIs (Dual-SIM) benutzt. Beide Variante haben ein true zurückgegeben.

Ich habe die Nummern bei mir direkt im Source Code eingetragen.

Möglicherweise habe ich die Fehlerquelle. Ich musste meine Zahlen explizit mit einem L angegeben, also z.B.

long imei = 1234L;

Der Grund ist, dass ein Integer diese große Zahl nicht speichern kann.

Deine Aufruf (Popup.readInt()) für den Erhalt der Zahl deutet darauf hin, dass du ein Interger bekommst. Der Integer wird dann implizit in ein long umgewandelt.

Wegen dem zwischenzeitlichen Integer sind vermutlich ein paar Zahlen verloren gegangen. Für diese Überprüfung ist der Algorithmus da.

Daher empfiehlt sich gleich eine Eingabe als IntArray (int[]) oder als String. Dort könnte die Zahl auch 100 Zeichen lang sein.

0

Ist doch schon alles fertig, musst nur noch deinen Methodenaufruf auswerten, z.B.

System.out.println("Passt" + (luhnTesten(z) ? ":)" : "nicht :("));

Momentan testet dein Programm zwar, aber es macht nichts mit dem Ergebnis.