ISBN mit Prüfnummer überprüfen

Gina25

Mitglied
Hallo :)

Ich habe gerade angefangen zu studieren und bin somit noch relativ unerfahren mit Java.

Nun haben wir eine Übungsaufgabe bekommen, die mir den Schlaf raubt.
Wir sollen ein Programm schreiben, welches eine 13-stellige ISBN überprüfen kann.

Der User soll also die ISBN im Terminal eingeben und das Programm berechnet dann, ob die Nummer richtig oder falsch ist. Ist sie falsch, soll das Programm die Prüfziffer (die 13.te Zahl) ändern, sodass die Nummer richtig ist.

Dies wird mithilfe eines Rechenweges berechnet. Die erste Zahl der ISBN wird mit 1 multipliziert, die zweite mit 3, die nächste wieder 1, die darauf mit 3, und so weiter. Das wird mit den ersten 12 Zahlen gemacht.

Die Prüfziffer ist nun die Differenz von dem eben errechneten Ergebnis bis zur nächsten durch 10 teilbaren Zahl.

Hier ein Beispiel: ISBN: 978-3-8274-1631-5
105 = 9 + 3 ∗ 7 + 8 + 3 ∗ 3 + 8 + 3 ∗ 2 + 7 + 3 ∗ 4 + 1 + 3 ∗ 6 + 3 + 3 ∗ 1
5 = 110 − 105
5 ist somit die richtige Prüfziffer.

Ich bin nun schon so weit gekommen, dass der User die Nummer eingeben kann und das Programm checkt, ob die Nummer 13-stellig ist oder nicht.
Jedoch habe ich einfach überhaupt keine Idee wie ich den oben genannten Rechenweg programmieren soll.

Ich hoffe jemand kann mir helfen :(


Anbei ein Bild meines bisherigen "Erfolgs".
 

Anhänge

  • ISBN.jpg
    ISBN.jpg
    76,7 KB · Aufrufe: 202

rme

Top Contributor
Hallo :)

Am Anfang ist es oft leichter, sich die einzelnen Schritte erstmal in natürlicher Sprache zu überlegen und erst danach langsam anzufangen, die einzelnen Teile der Überlegung nach Java zu übersetzen.

Kannst du versuchen, das Problem in mehrere Teilprobleme zu gliedern und mit normaler Sprache zu beschreiben, was dort jeweils passieren muss? Zum Beispiel so:

- einlesen der Eingabe des Benutzers
- Prüfen, ob die Länge korrekt ist
- ...

Wenn du das als ersten Schritt für die gesamte Aufgabe schaffst, können wir versuchen, die Schritte Stück für Stück nach Java zu übersetzen :) Das ist glaube ich besser, als dir einfach eine Lösung oder zu tiefe Tipps vorzuwerfen, denn du möchtest ja hoffentlich etwas dabei lernen.. und das funktioniert nach meiner Erfahrung am besten, wenn du dabei deine eigene Denkweise und Sicht auf das Problem behalten kannst.
 
Zuletzt bearbeitet:

Saheeda

Top Contributor
@Gina

Für die abwechselnde Multiplikation kann dir der Modulo-Operator (%) behilflich sein. Damit kannst du den Rest einer Division berechnen und damit auch, ob eine Zahl gerade ist, oder nicht:

2%2 = 0 --> gerade
3%2 = 1 --> ungerade

Gehe in einer Schleife über deinen string, wandle die einzelnen Ziffern in Zahlen um und führe dann je nach Index eine andere Berechnung durch:
Java:
for( int i = 0; i<a.length; i++){
			if(i%2 == 0) {
				//Berechnungen der geraden Indizes
			} else {
				//Berechnungen der ungeraden Indizes
			}
		}

Achtung: Die Zählung beginnt bei Index 0, nicht 1!
 

Gina25

Mitglied
Okay, also Einlesen der Eingabe und Prüfen der Länge habe ich ja nun schon.

Ich denke der nächste Schritt wäre dann die abwechselnde Multiplikation der ISBN mit 1 und 3, oder?

Wir haben als Hinweis bekommen mit char charAt zu arbeiten, sowie dass die Zeichen '0',..,'9' die int-Werte 48,...,57 haben. Allerdings hilft mir dieser Hinweis einfach null weiter, weil ich gar nicht weiß was ich mit charAt anfangen soll. :/
 

Gina25

Mitglied
@Saheeda,

was genau meinst du mit "Berechnung des geraden/ungeraden Indizes"?

Wahrscheinlich stehe ich gerade total auf dem Schlauch, aber ich verstehe immer noch nicht wo bei deinem Code multipliziert wird :noe:
 

rme

Top Contributor
Die eingegeben Ziffern entstammen ja einem Text - es wäre für den Benutzer bisher nicht verboten, auch ein "a" oder so einzugeben. Und in einem Text sind Ziffern anders codiert als Zahlen, mit denen man intuitiv rechnen könnte. charAt wird dir also z.B. 48 liefern, wenn der Benutzer an der Stelle eine '0' eingegeben hat. Und 49, wenn er eine '1' eingegeben hat usw. Das sind die Codierungen für Ziffern innerhalb einer Zeichenkette. Zum Rechnen brauchst du aber den tatsächlichen Wert der Ziffer. Erkennst du einen mathematischen Zusammenhang, wie du von 48 auf 0, von 49 auf 1 usw. kommst? Also eine Berechnung, um von textuellen Ziffern in Zahlen zu konvertieren? Tipp: Ist eine Grundrechenart :)
 

Gina25

Mitglied
@rme, also auf dem ersten Blick würde ich jetzt sagen, man zieht einfach immer 48 ab :D also 48-48=0, 49-48=1, usw.
Das wäre jetzt die Berechnung die mir als erstes einfallen würde, ich hoffe du meinst das auch :)

@Joose, stimmt du hast Recht :) Programmiere allerdings in einer Virtuellen Box mit Ubuntu, und kann daraus nichts kopieren :/ ich tippe es schnell mal selbst ab und poste es dann hier drunter :)
 

Saheeda

Top Contributor
Du möchtest abwechselnd mit 1 und mit 3 multiplizieren:
1. Zahl --> *1
2. Zahl --> *3
3. Zahl --> *1
4. Zahl --> *3
etc.
Man kann also sagen, dass jede Zahl an einer geraden Stelle mit 3 multipliziert wird, jede an einer ungeraden Stelle mit 1.


Die einzelnen Chars eines Strings sind durchnummeriert (mit einem Index / Plural Indizes) versehen.
Durch die Nummerierung kann man mit einer Schleife über den String gehen ("iterieren") und jedes einzelne Zeichen überprüfen.


Meine Kommentare sollen heißen, dass du an diesen Stellen die entsprechenden Berechnungen eintragen müsstest.
 
Zuletzt bearbeitet:

rme

Top Contributor
Deine Idee, 48 abzuziehen, ist genau richtig :) Zusammen mit dem Vorschlag von Saheeda kannst du nun damit die Berechnung durchführen. Statt 48 kannst du übrigens auch '0' abziehen - dadurch entstehen Ausdrücke der Form '0' - '0' = 0, '1' - '0' = 1 usw., weil die Ziffern fortlaufend codiert sind. Und weil '0' eben dasselbe wie 48 bedeutet. Ist dann etwas leserlicher :)
 

Gina25

Mitglied
@Saheeda Ahhh, jetzt habe ich es verstanden, danke :)


Hier mein Code:

Java:
import java.util.Scanner;

public class Isbn {
     public static void main (String[] args) {
          Scanner sc = new Scanner(System.in);
          String isbn;

              System.out.print("Gib ISBN Nummer ein");
          isbn = sc.nextLine();
          sc.close();

          isbn = isbn.replaceAll("( |-)", "");

          boolean isValid = false;
          if (isbn.length() == 13) {
              isValid = true;
        } else {
             isValid = false;
        }
   }
}
 
Zuletzt bearbeitet:

Saheeda

Top Contributor
Geh mal logisch ran:
charAt liefert die den Character an einer bestimmten Stelle. Wann brauchst du diese Information? Und was machst du dann damit?
 

freakdran

Mitglied
Zu Wann und Wo charAt verwenden:
Ihr habt doch sicher schon mit Schleifen, also while oder for gearbeitet, oder?
charAt gibt dir ja die char an einer bestimmten stelle, also müsstest jede Stelle einmal durchgehen um so die Zahl zu überprüfen die an der Stelle steht. Und dann kannst du ja erst berechnen, vorher hast du ja gar keine Werte.
 

Shams

Aktives Mitglied
Ich habe mir darüber mal ein Paar Gedanken gemacht, und habe den folgenden Code ersonnen, aber ich weiß nicht, ob das so gut geht, also ich poste den Code mal ohne Gewähr.

Code:
import java.util.Scanner;


public class Main {

	private static boolean corrected = false;
		
	private String korrigierePruefZiffer(int pruefZiff,String isbn){
		
		
		if ( pruefZiff != Integer.parseInt( new String(new char[]{isbn.toCharArray()[isbn.toCharArray().length-1]})  )){
		
			corrected = true;
			
			return isbn.substring(0,(isbn.toCharArray().length-2)) + new Integer(pruefZiff).toString();
			
		}
		
		
		corrected = false;
		
		return isbn;
	}
	
	private int pruefZiffer(String isbn) {

		int pruefsumme = 0;
		int pruefsummeGerade=0;
		int pruefsummeUngerade=0;
		
      for(int i=0;i<isbn.toCharArray().length;i++){
             
    	  if(i%2==0){
    		  pruefsummeGerade += Integer.parseInt(isbn.substring(i,i+1));
    		 
    		 
    	  }
    	  else{
    		  pruefsummeUngerade += (Integer.parseInt(isbn.substring(i,i+1))*3);
    		  
    	  }
      }  
      
      
      pruefsummeUngerade -= Integer.parseInt( new String(new char[]{isbn.toCharArray()[isbn.toCharArray().length-1]})  );
      pruefsumme = pruefsummeGerade + pruefsummeUngerade;
      
      int nextDivisibleByTen = 0;
              while(pruefsumme%10!=0){
            	  pruefsumme++;
            	  nextDivisibleByTen++;
            	  
              }
              
              return nextDivisibleByTen;
      
	}
	
	
	private String isCorrected() {
		
		if(corrected){
			return " Es wurde die Pruefziffer korrigiert.";
		}

		    return " Es wurde nichts korrigiert.";
		
	}
	
	public static void main(String[] args) {

Main m = new Main();		
		
Scanner sc = new Scanner(System.in);

String isbn = "";

System.out.println("Gibt mir die isbn an!");

isbn = sc.nextLine();
sc.close();

isbn = isbn.replaceAll("-", "");


if(isbn.length() != 13){
	System.out.println("The number is invalid, its length is not correct.");
	System.exit(-1);
}
	else{
		
		System.out.println("Das ist die richtige Pruefziffer: " + m.pruefZiffer(isbn));
		System.out.println("Das ist die richtige ISBN: " + m.korrigierePruefZiffer(m.pruefZiffer(isbn),isbn) + m.isCorrected());
	}

	}



}
 

Flown

Administrator
Mitarbeiter
Wieso werden eigentlich immer Lösungen gepostet? Das hilft keinem und dann noch so eine Lösung. :noe:
 

Gina25

Mitglied
Habe nun eure Vorschläge mit eingearbeitet. Jedoch hänge ich bei dem Problem, dass er unterscheiden soll, ob die Prüfziffer schon richtig ist oder nicht. Bisher berechnet das Programm die korrekte Prüfziffer, doch prüft vorher nicht, ob sie schon richtig ist.

Java:
import java.util.Scanner;
    
public class Isbn {
    public static void main (String[] args) {
        Scanner sc = new Scanner(System.in);
        String isbn;
     
        System.out.print("Gib ISBN Nummer ein");
        isbn = sc.nextLine();
        sc.close();
     
        isbn = isbn.replaceAll("( |-)", "");
     
        boolean laenge = false;
        if (isbn.length() == 13) {
        laenge = true;
        } else {
        laenge = false;
        System.out.print("ISBN Nummer ist ungültig.");
        }
        
        int z = 0;
		int k=0;
		int j=0;

        for( int i = 0; i<isbn.length(); i++){
        char result = isbn.charAt(i);
        if(i%2 == 0) {
            k += Integer.parseInt(isbn.substring(i,i+1));
        } else {
            j += (Integer.parseInt(isbn.substring(i,i+1))*3);;
            }
           
        }
       j -= Integer.parseInt( new String(new char[]{isbn.toCharArray()[isbn.toCharArray().length-1]})  );
      z = k + j; 

        int x = 0;
              while(z%10!=0){
            	  z++;
            	  x++;
            	  
              }
              
      System.out.println("Die ISBN ist üngültig. Die richtig Prüfziffer lautet:" + x);
	
	   
            
    }
}
 

Flown

Administrator
Mitarbeiter
Also ich kann und will das einfach nicht so dastehen lassen. Bei so einem Code stellt es mir die Nackenhaare auf.
Hier mal ein korrekter Code:

Java:
import java.util.Scanner;

public class ISBNChecker {
  public static void main(String... args) {
    try (Scanner scanner = new Scanner(System.in)) {
      System.out.println("Geben Sie bitte die ISBN ein('-' werden ignoriert): ");
      String isbn = scanner.nextLine().replace("-", "");
      if (isbn.length() != 13) {
        throw new IllegalArgumentException("ISBN muss aus 13 Zahlen bestehen.");
      }
      int sum = 0;
      for (int i = 0; i < isbn.length() - 1; i++) {
        char cur = isbn.charAt(i);
        if (!Character.isDigit(cur)) {
          throw new IllegalArgumentException("ISBN darf nur aus Ziffern bestehen.");
        }
        sum += Character.getNumericValue(cur) * (i % 2 == 0 ? 1 : 3);
      }
      char oldCheckchar = isbn.charAt(isbn.length() - 1);
      if (!Character.isDigit(oldCheckchar)) {
        throw new IllegalArgumentException("Prüfziffer ist keine Ziffer.");
      }
      int oldCheckNumber = Character.getNumericValue(oldCheckchar);
      int newCheckNumber = 10 - sum % 10;
      if (oldCheckNumber != newCheckNumber) {
        System.out.println("Prüfziffer wird von " + oldCheckNumber + " auf " + newCheckNumber + " korrigiert.");
        isbn = isbn.substring(0, isbn.length() - 1) + String.valueOf(newCheckNumber);
      } else {
        System.out.println("ISBN is korrekt.");
      }
      for (int i = 0; i < isbn.length(); i++) {
        if (i == 3 || i == 4 || i == 6 || i == 12) {
          System.out.print("-");
        }
        System.out.print(isbn.charAt(i));
      }
      System.out.println();
    }
  }
}
 
Zuletzt bearbeitet:

Saheeda

Top Contributor
@Shams

Welchen Sinn hat hier die erste Zeile? Du zerlegst einen String in ein Char-Array und bastelst es direkt wieder zu einem String zusammen. Auf die letzte Position könntest du auch direkt mit charAt() zugreifen.
Java:
if ( pruefZiff != Integer.parseInt( new String(new char[]{isbn.toCharArray()[isbn.toCharArray().length-1]})  )){
		
			corrected = true;
			
			return isbn.substring(0,(isbn.toCharArray().length-2)) + new Integer(pruefZiff).toString();
			
		}
 

Gina25

Mitglied
Sooo, ich habe es jetzt dank eurer Hilfe geschafft, dass alles nahezu einwandfrei klappt :)
Vielen Dank schonmal!

Nun habe ich aber noch eine letzte Frage, und zwar hast du @Flown ja eine Möglichkeit gezeigt, dass die Bindestriche wieder bei der Ausgabe angezeigt werden. In unseren Beispiel-ISBN's variieren die Bindestriche jedoch, also kann man denen keine genaue Stelle zuweisen.

Ist es möglich, dass das Programm sich anhand der eingegeben ISBN die Stellen der Bindestriche selbst merkt und diese dann auch bei der Ausgabe wieder da einsetzt?
Und wenn ja, könnt ihr mir einen Tipp geben wie dies funktioniert? :oops:
 

MightyMischi

Neues Mitglied
Hallo zusammen!
Also noch ein "TUler" unterwegs hier! ;-)

Ich habe mein Programm anders gelöst, es zählt die Anzahl der Striche, und die Ziffer hinter dem 4. Strich ist die Prüfsumme.
Nun gehe ich die ISBN als String Zeichen für Zeichen durch, prüfe via try/catch ob es sich in einen Integer übersetzen lässt - wenn nicht, ist das Zeichen an der Stelle eben ein Strich, oder ein anderes Trennzeichen. Die rausgesammelten Ziffern addiere ich dann je nach ihrer Position (gerade/ungerade, via modulo 2) entweder so oder mit 3 multipliziert gleich auf die Prüfsumme, diese jage ich dann durch eine "Formel" aus Modulos und erhalte so die korrekte, fertige Prüfsumme. Dann vergleiche ich diese mit der Zahl hinter dem letzten Strich der ISBN und ersetze diese ggf. durch die richtige, berechnete Prüfsumme. Abschließend gebe ich alles aus... Hilft dir das irgendwie?

Liebe Grüße! :)
 
Zuletzt bearbeitet:

Flown

Administrator
Mitarbeiter
Sicher geht das. Du iterierst am Anfang, vor dem replace, über deine Eingabe und speicherst dir alle Stellen an dem ein '-' steht in ein Array/Liste/was auch immer ... .
Oder du machst es mit einem Regex mit einem Pattern und Matcher.

Zum Schluss, bei der Ausgabe, fügst du dann die '-' zu der Konsole hinzu.
 

Neue Themen


Oben