# ISBN mit Prüfnummer überprüfen



## Gina25 (19. Nov 2014)

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".


----------



## rme (19. Nov 2014)

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.


----------



## Saheeda (19. Nov 2014)

@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:

```
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 (19. Nov 2014)

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 (19. Nov 2014)

@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 (19. Nov 2014)

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


----------



## Joose (19. Nov 2014)

Gina25 hat gesagt.:


> Anbei ein Bild meines bisherigen "Erfolgs".



Es ist immer praktischer den Code direkt im Forum zu posten statt einem Bild von deinem Code! 
Der Vorteil die Helfer müssen deine Code nicht mühsam abtippen sondern können diesen einfach per Copy&Paste übernehmen.


----------



## Gina25 (19. Nov 2014)

@rme, also auf dem ersten Blick würde ich jetzt sagen, man zieht einfach immer 48 ab  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 (19. Nov 2014)

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.


----------



## rme (19. Nov 2014)

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 (19. Nov 2014)

@Saheeda Ahhh, jetzt habe ich es verstanden, danke 


Hier mein Code:


```
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;
        }
   }
}
```


----------



## Gina25 (19. Nov 2014)

Und wo muss ich charAt einfügen? Bei der Berechnung oder schon vorher?


----------



## Saheeda (19. Nov 2014)

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 (19. Nov 2014)

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.


----------



## Flown (19. Nov 2014)

[edit]Ins richtige Unterforum verschoben[/edit]


----------



## Shams (19. Nov 2014)

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.


```
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 (19. Nov 2014)

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


----------



## Gina25 (20. Nov 2014)

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.


```
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 (20. Nov 2014)

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:


```
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();
    }
  }
}
```


----------



## Saheeda (20. Nov 2014)

@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.

```
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 (20. Nov 2014)

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?


----------



## MightyMischi (20. Nov 2014)

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!


----------



## Flown (21. Nov 2014)

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.


----------

