Java ersetze ß mit ss - ohne replace!

Endless Storm

Commander
Registriert
Dez. 2008
Beiträge
2.158
Hallo Freunde,

ich nehme im Studium gerade arrays durch, eigentlich ist es ja verständlich und klar, dachte ich^^

Die Aufgabenstellung lautet: Beliebig Buchstaben aus einem Text zu ersetzen, dabei wird als Wunschergebnis ß durch ss ersetzt.

Das Ersetzen eines Buchstaben durch einen anderen klappt wunderbar, jedoch erhalte ich bei Unlauten (zB. dem ß) in der Ausgabe kein "ß", sondern "ß". Zudem bekomme ich es nicht hin, einen Buchstaben durch eine Zeichenkette zB. "ss" zu ersetzen.

Den Befehl replace haben wir noch nicht durchgenommen, dürfen den also leider nicht verwenden :(

Code:
import inout.Console;
 
class ZeichenErsetzen
{ 
 public static void main (String args[]) 
 { 
  char text[], textNeu [];
  char zuErsetzen, ersetzenDurch;
  System.out.println
   ("Bitte geben Sie eine Zeichenkette ein");
  text = Console.readCharArray();
  textNeu = text;
  System.out.println
   ("Bitte geben Sie das zu ersetzende Zeichen ein:");
  zuErsetzen = Console.readChar();
  System.out.println
   ("Bitte geben Sie die einzusetzende Zeichenkette ein:");
  ersetzenDurch = Console.readChar();
  int laenge = text.length;
  int posAuf = 0, posAb = laenge-1;
  while (posAuf < posAb)
  {
   if (text[posAuf] == zuErsetzen)
   {
       textNeu[posAuf] = ersetzenDurch;
    }
    else
    textNeu[posAuf] = text[posAuf];
     // endif
    posAuf++;
  }
  System.out.println("Ausgabe:"); 
  for (int i=0; i <= text.length-1; i++)    
    System.out.print(textNeu[i]);
 } 
}


Gedanklich habe ich zudem probiert, den ersetzenden Teil auch als array zu speichern, das würde auch funktionieren, jedoch überschreibe ich dann mehr als nur eine Stelle. Funktionieren würde dies, wenn ich 2 gegen 2 ersetze oder so.

Weiter versuchte ich, die Variablen ersetzeDurch als String zu deklarieren, aber er ersetzt dann keinen char in String...


Vielleicht habt ihr Ideen wie ich dies umsetzen könnte.
 
Das Ersetzen eines Buchstaben durch einen anderen klappt wunderbar, jedoch erhalte ich bei Unlauten (zB. dem ß) in der Ausgabe kein "ß", sondern "ß".

Das liegt höchstwahrscheinlich daran, dass entweder dein Quellcode nicht im Unicode format gespeichert wird (siehe eclipse datei einstellungen falls du es benutzt) oder die Konsole kein Unicode unterstützt. kann man aber auch umstellen
 
Grüße,

das ß ist bei der Ausgabe möglicherweise zerschossen, weil die Klasse Console da Mist baut. Java verarbeitet die Zeichen intern in UTF-8. Wenn die Console das aber mit dem Windows-nativen Encoding einliest (ich glaub cp1252 oder so), gibt die falsche Encodings zurück.

Die Console-Klasse ist blöderweise keine Standard-Library. Daher kann ich auch nicht sagen, was die falsch macht (hab sie halt nicht^^).

Wenn du einzelne Zeichen durch Zeichenketten ersetzen willst, kannst du das Array 'textNeu' nicht durch kopieren von text initialisieren, da du nicht weißt, wie lang textNeu wird. Du musst im Prinzip erst die zu ersetzenden Zeichen zählen, dann mit der Anzahl der Zeichen in der einzusetzenden Zeichenkette multiplizieren. Dann kommst du auf die Länge von textNeu.

Zeile 33 sollte auch nur mit der Länge von textNeu arbeiten, da diese sich möglicherweise in der Länge von text unterscheidet.
 
Jeder einzelne Buchstabe wird in einem "Fach" gespeichert, daher kannst du ein ß nicht durch ss ersetzen
Sie müssten daher die beiden s in jeweils ein Fach speichern und dazu die anderen Buchstaben jeweils um einen nach hinten verschieben.

In Zeile 18 wird außerdem das Doppel s in ein Char gespeichert, welches aber auch nur ein Buchstabe speichern kann.
Sie müssten es als String auslesen.
 
Also ich habe mir dahingehend auch Gedanken gemacht, meine Lösung sieht nun vor, dass ich zunächst Prüfe, ob die zu ersetzende Zeichenkette mehr als 1 Zeichen enthält, dann zählt es die zu ersetzenden Zeichen und erstellt ein neues array mit der passenden größe, anschließend kopiert es Zeichen für Zeichen in die neue, wenn er auf ein Zeichen stößt, was er ersetzen soll, macht er dort eine Schleife und arbeitet erst diese ab.

In mehreren Durchläufen erfolgreich getestet, egal wieviele Zeichen ich ersetzen will (ausgehend von nur einem Buchstaben der ersetzt werden soll).

Das "ß"-Problem bleibt aber weiterhin.


Mal noch eine Frage am Rande, wann entscheide ich mich für die while-Schleife und wann für die for-Schleife?
Irgendwie mache ich es momentan so, wenn ich etwas zählen lassen will, was einen neuen Zähler benötigt (zB. i = 1), dann mache ich die for-Schleife, wenn ich warten will, bis eine vorhandene Variable etwas erreicht, wähle ich while...
Gibt es da feste Regeln, oder Vorschläge, wann ich was nutzen sollte?


Hier mal meine Lösung:

Code:
import inout.Console;
 
class ZeichenErsetzen
{ 
 public static void main (String args[]) 
 { 
  char text[], textNeu [], ersetzenDurch [];
  char zuErsetzen;
  System.out.println
   ("Bitte geben Sie eine Zeichenkette ein");
  text = Console.readCharArray();
  textNeu = text;
  System.out.println
   ("Bitte geben Sie das zu ersetzende Zeichen ein:");
  zuErsetzen = Console.readChar();
  System.out.println
   ("Bitte geben Sie die einzusetzende Zeichenkette ein:");
  ersetzenDurch = Console.readCharArray();
  int laenge = text.length;
  int laengeErsetzen = ersetzenDurch.length;
  int posAuf = 0, posAb = laenge-1;
  int posAufNeu = 0, posAbNeu = 0;
  int anzahlErsetzen = 0;
  if (laengeErsetzen > 1)
  {
      for (int i = 0; i <= posAb; i++)
      { 
          if (text[i] == zuErsetzen)
          anzahlErsetzen++;
      }
      textNeu = new char[laenge + (laengeErsetzen-1) * anzahlErsetzen];
      posAbNeu = textNeu.length-1;
      while (posAuf < laenge)
      {
          if (text[posAuf] == zuErsetzen)
          {
              for (int j = 0; j <= laengeErsetzen-1; j++)
              {
                  textNeu[posAufNeu] = ersetzenDurch[j];
                  posAufNeu++;
              }
          }
          else
          {
              textNeu[posAufNeu] = text[posAuf];
              posAufNeu++;
          }
          posAuf++;
      }
    }
  else
  {
      while (posAuf < posAb)
      {
          if (text[posAuf] == zuErsetzen)
          textNeu[posAuf] = ersetzenDurch[0];
          else
          textNeu[posAuf] = text[posAuf];
          // endif
          posAuf++;
        }
  }
  System.out.println("Ausgabe:"); 
  for (int i=0; i <= textNeu.length-1; i++)    
    System.out.print(textNeu[i]);
 } 
}


In "Console" stehen vom Studium aus notwendige Methoden um zB. Konsoleneingaben zu realisieren. Gerne kann ich aber auch kurz den Inhalt hier separat posten wenn es hilfreich ist?!

Wie müsste ich die "Console" denn speichern, damit das ß funktioniert? Oder muss dafür eine neue Zeile irgendwo ergänzt werden?


Hier der Code von der Console:

Code:
package inout;
   
import java.util.Scanner;
import java.util.Calendar;
import java.util.Locale;
import java.util.Date;
import java.util.NoSuchElementException;
import java.util.InputMismatchException;
import java.util.regex.Pattern;
import java.text.ParseException;
import java.text.DateFormat;

/** Diese Klasse stellt Methoden zur Verfügung,
 * um Texte und einfache Typen von der Konsole einzulesen.
 * Die Ausnahmebehandlung ist Aufgabe des Aufrufers.
 */
public class Console
{
 private static Scanner sc;
 
 //Unterdrückung des default-Konstruktor,
 //um eine Objekterzeugung zu verhindern
 private Console()
 {
  //Dieser Konstruktor wird nie aufgerufen
 }
 
 /**Liest eine Zeile von der Konsole
  * @return Eingelesene Zeile vom Typ String.
  * @exception NoSuchElementException: 
  *    Es wurde keine Eingabezeile gefunden.
  * @exception IllegalStateException: 
  *    Die verwendete Methode ist nicht geöffnet.
  */
 public static String readString() 
  throws NoSuchElementException, IllegalStateException
 {
    Scanner sc = new Scanner(System.in);
    return sc.nextLine();
 }
 
 /**Liest eine Zeile von der Konsole
  * @return Eingelesene Zeile vom Typ char[].
  * @exception NoSuchElementException: 
  *    Es wurde keine Eingabezeile gefunden.
  * @exception IllegalStateException: 
  *    Die verwendete Methode ist nicht geöffnet.
  */
 public static char[] readCharArray() 
  throws NoSuchElementException, IllegalStateException
 {
    sc = new Scanner(System.in);
    String text = sc.nextLine();
    return text.toCharArray();
 }
        
 /**Liest einen booleschen Wert von der Konsole
  * @return Boolescher Wert true oder false.
  * @exception NoSuchElementException: 
  *    Es wurde keine Eingabezeile gefunden.
  * @exception IllegalStateException: 
  *    Die verwendete Methode ist nicht geöffnet.
  * @exception InputMismatchException: 
  *    Die Eingabe entspricht nicht dem Typ.
  */
 public static boolean readBoolean() throws 
   InputMismatchException, NoSuchElementException, 
   IllegalStateException
 {
    sc = new Scanner(System.in);
    return sc.nextBoolean();
 }
 
 /**Liest eine ganze Zahl vom Typ int von der Konsole
  * @return Ganze Zahl vom Typ int.
  * @exception InputMismatchException: 
  *    Die Eingabe entspricht nicht dem Typ.
  * @exception NoSuchElementException: 
  *    Es wurde keine Eingabezeile gefunden.
  * @exception IllegalStateException: 
  *    Die verwendete Methode ist nicht geöffnet.
  */
 public static int readInt() throws 
   InputMismatchException, NoSuchElementException, 
   IllegalStateException
 {
    return new Scanner(System.in).nextInt();
 }
 
 /**Liest eine ganze Zahl vom Typ long von der Konsole
  * @return Ganze Zahl vom Typ long
  * @exception InputMismatchException: 
  *    Die Eingabe entspricht nicht dem Typ.
  * @exception NoSuchElementException: 
  *    Es wurde keine Eingabezeile gefunden.
  * @exception IllegalStateException: 
  *    Die verwendete Methode ist nicht geöffnet.
  */
 public static long readLong() throws 
   InputMismatchException, NoSuchElementException, 
   IllegalStateException
 {
    return new Scanner(System.in).nextLong();
 }

 /**Liest eine Gleitpunktzahl vom Typ float von der Konsole
  * Englische Notation: Trennung der 
  * Nachkommastellen durch Punkt
  * @return Gleitpunktzahl vom Typ float
  * @exception InputMismatchException: 
  *    Die Eingabe entspricht nicht dem Typ.
  * @exception NoSuchElementException: 
  *    Es wurde keine Eingabezeile gefunden.
  * @exception IllegalStateException: 
  *    Die verwendete Methode ist nicht geöffnet.
  */
  public static float readFloatPoint() throws 
   InputMismatchException, NoSuchElementException, 
   IllegalStateException
 {
    Locale.setDefault(Locale.ENGLISH);
    return new Scanner(System.in).nextFloat();
 }

 /**Liest eine Gleitpunktzahl vom Typ float von der Konsole
  * Deutsche Notation: Trennung der 
  * Nachkommastellen durch Komma
  * @return Gleitpunktzahl vom Typ float
  * @exception InputMismatchException: 
  *    Die Eingabe entspricht nicht dem Typ.
  * @exception NoSuchElementException: 
  *    Es wurde keine Eingabezeile gefunden.
  * @exception IllegalStateException: 
  *    Die verwendete Methode ist nicht geöffnet.
  */
 public static float readFloatComma() throws 
   InputMismatchException, NoSuchElementException, 
   IllegalStateException
 {
    Locale.setDefault(Locale.GERMAN);
    return new Scanner(System.in).nextFloat();
 }

 /**Liest eine Gleitpunktzahl vom Typ double von der Konsole
  * Englische Notation: Trennung der 
  * Nachkommastellen durch Punkt
  * @return Gleitpunktzahl vom Typ double
  * @exception InputMismatchException: 
  *    Die Eingabe entspricht nicht dem Typ.
  * @exception NoSuchElementException: 
  *    Es wurde keine Eingabezeile gefunden.
  * @exception IllegalStateException: 
  *    Die verwendete Methode ist nicht geöffnet.
  */
 public static double readDoublePoint() throws 
   InputMismatchException, NoSuchElementException, 
   IllegalStateException
 {
    Locale.setDefault(Locale.ENGLISH);
    return new Scanner(System.in).nextDouble();
 }
 
 /**Liest eine Gleitpunktzahl vom Typ double von der Konsole
  * Deutsche Notation: Trennung der 
  * Nachkommastellen durch Komma
  * @return Gleitpunktzahl vom Typ double
  * @exception InputMismatchException: 
  *    Die Eingabe entspricht nicht dem Typ.
  * @exception NoSuchElementException: 
  *    Es wurde keine Eingabezeile gefunden.
  * @exception IllegalStateException: 
  *    Die verwendete Methode ist nicht geöffnet.
  */
 public static double readDoubleComma() throws 
   InputMismatchException, NoSuchElementException, 
   IllegalStateException
 {
    Locale.setDefault(Locale.GERMAN);
    return new Scanner(System.in).nextDouble();
 }  

/**Liest ein Zeichen vom Typ char von der Konsole
 * @return Erstes eingegebene Zeichen vom Typ char.
 * @exception NoSuchElementException:
 *    Es wurde keine Eingabezeile gefunden.
 */
 public static char readChar() throws 
   NoSuchElementException,IllegalStateException
 {
    String s = new Scanner(System.in).next();
    return s.charAt(0);
 }

}
 
Endless Storm schrieb:
Wie müsste ich die "Console" denn speichern, damit das ß funktioniert? Oder muss dafür eine neue Zeile irgendwo ergänzt werden?

Das hat nichts mit Deinem Code zu tun, sondern liegt an der Eingabeauforderung (oder wie das Terminal bei Windows heißt). Wenn dort nicht das korrekte Encoding eingestellt bzw. kein Font verwendet wird, der die Zeichen unterstützt, werden manche Zeichen nicht korrekt angezeigt. Man kann mittels

Code:
C:> chcp 65001

auf Unicode wechseln, muss aber dann wie gesagt auch einen Font wählen, der damit klarkommt. Vielleicht reicht es sogar aus, nur den Font zu wechseln (etwa Inconsolata). Warum Windows immer noch nicht Unicode als Standard nutzt, ist mir ein Rätsel.

Noch eine Anmerkung zum Code: Dürft ihr auch keinen StringBuilder verwenden? Die Implementierung mit Arrays ist doch arg kompliziert. Ich würde mir auch von Anfang an angewöhnen, Code zu strukturieren und nicht alles in eine Methode zu packen.
 
soares schrieb:
Noch eine Anmerkung zum Code: Dürft ihr auch keinen StringBuilder verwenden? Die Implementierung mit Arrays ist doch arg kompliziert. Ich würde mir auch von Anfang an angewöhnen, Code zu strukturieren und nicht alles in eine Methode zu packen.

Momentan sollen wir nur verwenden, was wir bisher auch durchgenommen haben, also weder replace, noch StringBuilder. Wird aber noch kommen. Wie es aussieht, sollen wir wohl von anfang alles zu Fuß erlernen^^

Wie meinst du das mit dem Code strukturieren? Solange die Aufgaben noch recht klein sind, denke ich sind unterschiedliche Methoden eher nebensache, oder doch eher sinnvoll?

Etwas unsicher bin ich zudem noch bei Methoden, wie ich Inhalte von Variablen in andere Methoden übergebe und sie auch zurück bekomme. Deklarieren als static ist mir mittlerweile bekannt, aber muss man zur Übergabe in eine andere Methode jedes mal die Parameter in Klammern angeben, welche Variablen ich übergeben will? Macht der das nicht automatisch? Ich denke da nur daran, wenn ich mal viele Variablen übergeben wollte, muss ich ja alle aufführen... Geht das auch anders, schneller, sicherer (bevor man welche vergisst wenn man das Programm erweitert)?
 
Wenn du eine Methode mit 10 Parametern deklarierst, musst du beim Aufruf auch 10 Argumente übergeben.
Da die 10 Argumente wohl irgendwie zusammengehören, kann man das ganze insofern vereinfachen, indem man diese in eine Klasse kapselt und die betreffende Methode dort implementiert. Dann musst du keine Argumente mehr übergeben, da die Methode direkt auf die Klassenvariablen zugreifen kann (wenn ihr dann bei Instanzen/Objekten angekommen seid, mach daraus Instanzvariablen und die Methode nicht static)

Und solltest du mal ein Argument vergessen, dann klopft dir (spätestens) der Compiler auf die Finger. ;)
 
Endless Storm schrieb:
Wie meinst du das mit dem Code strukturieren? Solange die Aufgaben noch recht klein sind, denke ich sind unterschiedliche Methoden eher nebensache, oder doch eher sinnvoll?

Bei so kleinen Aufgaben ist das wie gesagt nicht entscheidend, ich würde es mir allerdings von Anfang richtig angewöhnen.

Endless Storm schrieb:
Etwas unsicher bin ich zudem noch bei Methoden, wie ich Inhalte von Variablen in andere Methoden übergebe und sie auch zurück bekomme. Deklarieren als static ist mir mittlerweile bekannt

Was man tunlichst vermeiden sollte, wenn es nicht zwingend erforderlich ist!


Endless Storm schrieb:
aber muss man zur Übergabe in eine andere Methode jedes mal die Parameter in Klammern angeben, welche Variablen ich übergeben will?

Innerhalb einer Klasse (bzw. Hierarchie je nachdem wie die Variable deklariert wurde) kann man auf die Instanzvariablen zugreifen, aber ich würde trotzdem die direkte Parameter-Übergabe vorziehen.

Endless Storm schrieb:
Macht der das nicht automatisch? Ich denke da nur daran, wenn ich mal viele Variablen übergeben wollte, muss ich ja alle aufführen... Geht das auch anders, schneller, sicherer (bevor man welche vergisst wenn man das Programm erweitert)?

Allzu viele Parameter sollten nicht zu übergeben sein, wenn man das Prinzip beherzigt, dass alle Code-Teile jeweils nur eine Aufgabe ausführen. Das lässt sich auf Klassen, wie auf Methoden anwenden.

Der Compiler beschwert sich allerdings in jedem Fall, wenn nicht alle Parameter übergeben wurden. Viele Methoden-Parameter bedeuten aber fast immer, dass man die Methode entweder aufspalten oder den Code gleich in eine eigene Klasse auslagern sollte.
 
Hi,

ich bin zwar kein Java Nutzer meine aber dass die Aufgabe mit merklich weniger Code umzusetzen wäre.

Versuch dich mal an einer Lösung mit array.shift. Oder einfach die Positionen der matches rausfinden und anhand der Positionen das array anpassen.

Denke man sollte ohne ein Duplikat arbeiten.

substring() erlaubt?

substring(0, searchpattern.lenght)

while(arr){
for(int i = 0;i <= searchpattern.length;++i){
make something;
arr.shift;
}
}

irgendwas in die Richtung.
 
Habs kurz und bündig ausimplementiert. Bei Fragen bitte stellen.
Getestet hab ichs nur ein zweimal aber sollte grundsätzlich alles können. Also einzelne Buchstaben durch einzele Buchstaben ersetzen, Zeichenketten durch Buchstaben ersetzen, Buchstaben durch Zeichenketten ersetzen und Zeichenketten durch Zeichenketten ersetzen :)

Die methode nimmt als Übergabeparameter den original-Text, das Zeichen/die Zeichenkette die ersetzt werden soll sowie das Zeichen/die Zeichenkette die stattdessen verwendet werden soll.
Das Ergebnis wird als char array zurückgegeben.

Code:
public char [] replaceChar(char [] text, char [] replace, char [] replacement) {
		
		StringBuffer newtext = new StringBuffer();
		
		for(int i = 0; i < text.length; i++) {
			
			if(text[i] == replace[0]) {
				
				int j = 0;
				while(j < replace.length && (i+j) < text.length 
                                        && text[i+j] == replace[j]) j++;
				
				if(j == replace.length) {
					newtext.append(replacement);
					i = i + j - 1;
					
				} else newtext.append(text[i]);
				
			} else newtext.append(text[i]);
		}
	
		return newtext.toString().toCharArray();
	}


Durch diese main-routine kann man das ganze auch testen: (dazu muss die replaceChar(...) methode static gemacht werden)

Code:
public static void main(String[] args) {
		
		String text = "Waß soll denn daß";
		String toreplace = "ß";
		String replacement = "ss";
		
		System.out.println("Old text: " + text);
		text = String.valueOf(replaceChar(text.toCharArray(), toreplace.toCharArray(), replacement.toCharArray()));
		
		System.out.println("New text: " + String.valueOf(text));
	}
 
Zuletzt bearbeitet:
hubertus1990 schrieb:
Durch diese main-routine kann man das ganze auch testen: (dazu muss die replaceChar(...) methode static gemacht werden)

Ist es falsch, dass man zum Testen die Methode static deklarieren muss. Es wäre auch höchst unüblich, dies zu tun. Unit-Tests sind vermutlich noch nicht durchgenommen. Das wäre der übliche Ansatz, eine Methode zu testen.

Man ruft die Methode ansonsten auf, indem man eine neue Klasseninstanz erzeugt:

Code:
new ZeichenErsetzen().replaceChar(...)


Davon ab ist es für Utility-Methoden, die über Klassengrenzen hinweg Verwendung finden, nicht ungewöhnlich sie in einer eigenen Klasse zur Verfügung zu stellen. Das ist dann aber auch der einzige Einsatzzweck für statische Methoden, main() ausgenommen. Ein Beispiel für eine solche Klasse mit globalen Utility-Methoden wäre java.util.Collections.
 
Ich hab zum Testen einfach eine main-routine geschrieben und dann die Methode in die gleiche Klasse gepackt, daher static. Natürlich ist das OOP-mäßig gesehen nicht korrekt, dabei gehts mir aber nicht. Ich zeige lediglich wie man Zeichen ersetzen kann.
 
hubertus1990 schrieb:
Ich hab zum Testen einfach eine main-routine geschrieben und dann die Methode in die gleiche Klasse gepackt, daher static. Natürlich ist das OOP-mäßig gesehen nicht korrekt, dabei gehts mir aber nicht. Ich zeige lediglich wie man Zeichen ersetzen kann.

Das ist ja auch OK, aber man sollte einen Anfänger nicht auf falsche Fährten locken und sagen, dass muss so.
 
Natürlich.
Man könnte zB. eine Klasse "CharacterReplacer" schreiben, die dann diese Methode implementiert.

Die Klasse CharacterReplacer.java
Code:
public class CharacterReplacer {

// ... hier wäre noch constructor oder ähnliches ...

public char [] replaceChar(char [] text, char [] replace, char [] replacement) {
		
		StringBuffer newtext = new StringBuffer();
		
		for(int i = 0; i < text.length; i++) {
			
			if(text[i] == replace[0]) {
				
				int j = 0;
				while(j < replace.length && (i+j) < text.length 
                                        && text[i+j] == replace[j]) j++;
				
				if(j == replace.length) {
					newtext.append(replacement);
					i = i + j - 1;
					
				} else newtext.append(text[i]);
				
			} else newtext.append(text[i]);
		}
	
		return newtext.toString().toCharArray();
	}
}

Um das nochmal für den Threadersteller festzuhalten müsste das ganze in der Main dann so aussehen:
Dies ist wieder eine andere Klasse, zB. Main.java oder Console.java ...

Code:
public static void main(String[] args) {
		
		String text = "Waß soll denn daß";
		String toreplace = "ß";
		String replacement = "ss";

                CharacterReplacer cr = new CharacterReplacer();
		
		System.out.println("Old text: " + text);
		text = String.valueOf(cr.replaceChar(text.toCharArray(), toreplace.toCharArray(), replacement.toCharArray()));
		
		System.out.println("New text: " + String.valueOf(text));
	}
 
Zuletzt bearbeitet:
Zunächst nochmal Danke für eure Beiträge, da merkt man, wie weit man erst ist :cool_alt:
Zur Erinnerung: replace dürfen wir noch nicht verwenden...

Mit der Übergabe von Variablen in andere Methoden, ich habe paar Tage vorher als Aufgabe gehabt, ein Symbolrätsel per Java zu lösen.

Das Ergebnis ist deutlich optimierungsfähig ich weiß, aber ich stand unter Zeitdruck und habe die Aufgabe gelöst bekommen, das zählt fürs erste. ;)


Sinn von dem Programm war es, eine Rechenaufgabe, in der die Zahlen durch Buchstaben ersetzt wurden, zu lösen, heißt die Buchstaben wieder zu Zahlen umzuwandeln.

B, E, H, S und T waren die Buchstaben aus der Rechenaufgabe.

Da ich hier Methoden ineinander verschachtelt habe und noch dazu einen Zähler "i" aus der letzten Methode öfters brauchte, habe ich das so gelöst:

Code:
public class Symbolraetsel
{
    static int i = 1;
    public static void main (String[] args)
    {
        int B = 0, E = 0, H = 0, S = 0, T = 0; //B, H und T nicht mit 1, sondern mit 0 deklariert
        ZahlB(B, E, H, S, T);
    }
    
    public static void ZahlB (int B, int E, int H, int S, int T) //Start mit dem ersten Buchstaben
    {
        boolean FertigB0 = false, FertigB1 = false, FertigB2 = false, FertigB3 = false, FertigB4 = false, FertigB5 = false, FertigB6 = false, FertigB7 = false, FertigB8 = false, FertigB9 = false; //FertigB0 als false deklariert
        for (;B <= 9; B++)
        {
            switch (B)
            {
                case 0:
                if (FertigB0 == true)
                continue;  //Springe zurück wenn Bedingung erfüllt
                else
                FertigB0 = true; ZahlE(B, E, H, S, T); break;
                case 1:
                if (FertigB1 == true)
                continue;
                else
                FertigB1 = true; ZahlE( B, E, H, S, T); break;
                case 2:
                if (FertigB2 == true)
                continue;
                else
                FertigB2 = true; ZahlE(B, E, H, S, T); break;
                case 3:
                if (FertigB3 == true)
                continue;
                else
                FertigB3 = true; ZahlE(B, E, H, S, T); break;
                case 4:
                if (FertigB4 == true)
                continue;
                else
                FertigB4 = true; ZahlE(B, E, H, S, T); break;
                case 5:
                if (FertigB5 == true)
                continue;
                else
                FertigB5 = true; ZahlE(B, E, H, S, T); break;
                case 6:
                if (FertigB6 == true)
                continue;
                else
                FertigB6 = true; ZahlE(B, E, H, S, T); break;
                case 7:
                if (FertigB7 == true)
                continue;
                else
                FertigB7 = true; ZahlE(B, E, H, S, T); break;
                case 8:
                if (FertigB8 == true)
                continue;
                else
                FertigB8 = true; ZahlE(B, E, H, S, T); break;
                case 9:
                FertigB9 = true; ZahlE(B, E, H, S, T); break;
                default: System.out.println("Fehler in Methode B"); break;
            }
        }
    }
    
    public static void ZahlE (int B, int E, int H, int S, int T)
    {
        boolean FertigE0 = false, FertigE1 = false, FertigE2 = false, FertigE3 = false, FertigE4 = false, FertigE5 = false, FertigE6 = false, FertigE7 = false, FertigE8 = false, FertigE9 = false;
        for (;E <= 9; E++)
        {
            switch (E)
            {
                case 0:
                if (FertigE0 == true | E == B)
                continue;
                else
                FertigE0 = true; ZahlH(B, E, H, S, T); break;
                case 1:
                if (FertigE1 == true | E == B)
                continue;
                else
                FertigE1 = true; ZahlH( B, E, H, S, T); break;
                case 2:
                if (FertigE2 == true | E == B)
                continue;
                else
                FertigE2 = true; ZahlH(B, E, H, S, T); break;
                case 3:
                if (FertigE3 == true | E == B)
                continue;
                else
                FertigE3 = true; ZahlH(B, E, H, S, T); break;
                case 4:
                if (FertigE4 == true | E == B)
                continue;
                else
                FertigE4 = true; ZahlH(B, E, H, S, T); break;
                case 5:
                if (FertigE5 == true | E == B)
                continue;
                else
                FertigE5 = true; ZahlH(B, E, H, S, T); break;
                case 6:
                if (FertigE6 == true | E == B)
                continue;
                else
                FertigE6 = true; ZahlH(B, E, H, S, T); break;
                case 7:
                if (FertigE7 == true | E == B)
                continue;
                else
                FertigE7 = true; ZahlH(B, E, H, S, T); break;
                case 8:
                if (FertigE8 == true | E == B)
                continue;
                else
                FertigE8 = true; ZahlH(B, E, H, S, T); break;
                case 9:
                if (E == B)
                break;
                FertigE9 = true; ZahlH(B, E, H, S, T); break;
                default: System.out.println("Fehler in Methode E"); break;
            }
        }
    }
    
    
    public static void ZahlH (int B, int E, int H, int S, int T)
    {
        boolean FertigH0 = false, FertigH1 = false, FertigH2 = false, FertigH3 = false, FertigH4 = false, FertigH5 = false, FertigH6 = false, FertigH7 = false, FertigH8 = false, FertigH9 = false;  //FertigH0 als false deklariert
        for (;H <= 9; H++)
        {
            switch (H)
            {
                case 0:
                if (FertigH0 == true | H == B | H == E)
                continue;
                else
                FertigH0 = true; ZahlS(B, E, H, S, T); break;
                case 1:
                if (FertigH1 == true | H == B | H == E)
                continue;
                else
                FertigH1 = true; ZahlS( B, E, H, S, T); break;
                case 2:
                if (FertigH2 == true | H == B | H == E)
                continue;
                else
                FertigH2 = true; ZahlS(B, E, H, S, T); break;
                case 3:
                if (FertigH3 == true | H == B | H == E)
                continue;
                else
                FertigH3 = true; ZahlS(B, E, H, S, T); break;
                case 4:
                if (FertigH4 == true | H == B | H == E)
                continue;
                else
                FertigH4 = true; ZahlS(B, E, H, S, T); break;
                case 5:
                if (FertigH5 == true | H == B | H == E)
                continue;
                else
                FertigH5 = true; ZahlS(B, E, H, S, T); break;
                case 6:
                if (FertigH6 == true | H == B | H == E)
                continue;
                else
                FertigH6 = true; ZahlS(B, E, H, S, T); break;
                case 7:
                if (FertigH7 == true | H == B | H == E)
                continue;
                else
                FertigH7 = true; ZahlS(B, E, H, S, T); break;
                case 8:
                if (FertigH8 == true | H == B | H == E)
                continue;
                else
                FertigH8 = true; ZahlS(B, E, H, S, T); break;
                case 9:
                if (H == B | H == E)
                break;
                FertigH9 = true; ZahlS(B, E, H, S, T); break;
                default: System.out.println("Fehler in Methode E"); break;
            }
        }
    }
    
    public static void ZahlS (int B, int E, int H, int S, int T)
    {
        boolean FertigS0 = false, FertigS1 = false, FertigS2 = false, FertigS3 = false, FertigS4 = false, FertigS5 = false, FertigS6 = false, FertigS7 = false, FertigS8 = false, FertigS9 = false;
        for (;S <= 9; S++)
        {
            switch (S)
            {
                case 0:
                if (FertigS0 == true | S == B | S == E | S == H)
                continue;
                else
                FertigS0 = true; ZahlT(B, E, H, S, T); break;
                case 1:
                if (FertigS1 == true | S == B | S == E | S == H)
                continue;
                else
                FertigS1 = true; ZahlT( B, E, H, S, T); break;
                case 2:
                if (FertigS2 == true | S == B | S == E | S == H)
                continue;
                else
                FertigS2 = true; ZahlT(B, E, H, S, T); break;
                case 3:
                if (FertigS3 == true | S == B | S == E | S == H)
                continue;
                else
                FertigS3 = true; ZahlT(B, E, H, S, T); break;
                case 4:
                if (FertigS4 == true | S == B | S == E | S == H)
                continue;
                else
                FertigS4 = true; ZahlT(B, E, H, S, T); break;
                case 5:
                if (FertigS5 == true | S == B | S == E | S == H)
                continue;
                else
                FertigS5 = true; ZahlT(B, E, H, S, T); break;
                case 6:
                if (FertigS6 == true | S == B | S == E | S == H)
                continue;
                else
                FertigS6 = true; ZahlT(B, E, H, S, T); break;
                case 7:
                if (FertigS7 == true | S == B | S == E | S == H)
                continue;
                else
                FertigS7 = true; ZahlT(B, E, H, S, T); break;
                case 8:
                if (FertigS8 == true | S == B | S == E | S == H)
                continue;
                else
                FertigS8 = true; ZahlT(B, E, H, S, T); break;
                case 9:
                if (S == B | S == E | S == H)
                break;
                FertigS9 = true; ZahlT(B, E, H, S, T); break;
                default: System.out.println("Fehler in Methode E"); break;
            }
        }
    }
    
    
        public static void ZahlT (int B, int E, int H, int S, int T)
    {
        boolean FertigT0 = false, FertigT1 = false, FertigT2 = false, FertigT3 = false, FertigT4 = false, FertigT5 = false, FertigT6 = false, FertigT7 = false, FertigT8 = false, FertigT9 = false;  //FertigT0 als false deklariert
        for (;T <= 9; T++)
        {
            switch (T)
            {
                case 0:
                if (FertigT0 == true | T == B | T == E | T == H| T == S)
                continue;
                else
                FertigT0 = true; Pruefung(B, E, H, S, T); break;
                case 1:
                if (FertigT1 == true | T == B | T == E | T == H| T == S)
                continue;
                else
                FertigT1 = true; Pruefung( B, E, H, S, T); break;
                case 2:
                if (FertigT2 == true | T == B | T == E | T == H| T == S)
                continue;
                else
                FertigT2 = true; Pruefung(B, E, H, S, T); break;
                case 3:
                if (FertigT3 == true | T == B | T == E | T == H| T == S)
                continue;
                else
                FertigT3 = true; Pruefung(B, E, H, S, T); break;
                case 4:
                if (FertigT4 == true | T == B | T == E | T == H| T == S)
                continue;
                else
                FertigT4 = true; Pruefung(B, E, H, S, T); break;
                case 5:
                if (FertigT5 == true | T == B | T == E | T == H| T == S)
                continue;
                else
                FertigT5 = true; Pruefung(B, E, H, S, T); break;
                case 6:
                if (FertigT6 == true | T == B | T == E | T == H| T == S)
                continue;
                else
                FertigT6 = true; Pruefung(B, E, H, S, T); break;
                case 7:
                if (FertigT7 == true | T == B | T == E | T == H| T == S)
                continue;
                else
                FertigT7 = true; Pruefung(B, E, H, S, T); break;
                case 8:
                if (FertigT8 == true | T == B | T == E | T == H| T == S)
                continue;
                else
                FertigT8 = true; Pruefung(B, E, H, S, T); break;
                case 9:
                if (T == B | T == E | T == H| T == S)
                break;
                FertigT9 = true; Pruefung(B, E, H, S, T); break;
                default: System.out.println("Fehler in Methode E"); break;
            }
        }
    }
    
    
    public static void Pruefung(int B, int E, int H, int S, int T)  //Prüfung der Rechenaufgabe und Übergabe an die Ausgabe
    {
        if (((H*100)+(E*10)+S)+((T*100)+(H*10)+E) == ((B*1000)+(E*100)+(S*10)+T))
        {
            Ausgabe(B, E, H, S, T);
        }
    }
    
    public static void Ausgabe(int B, int E, int H, int S, int T)
    {
        System.out.println
        ("Lösungs-Nr.: " + i + ": B = " + B + ", E = " + E + ", H = " + H + ", S = " + S + ", T = " + T + ":");
        System.out.println("  " + H + E + S);
        System.out.println("+ " + T + H + E);
        System.out.println("_____");
        System.out.println(" " + B + E + S + T);
        
        i++;
        
        //folgende if-Anweisungen wurde für die Prüfung hinzugefügt
        if (H == 0 & T == 0)
         System.out.println("H und T sind gleich 0");
        if (H == 0)
        System.out.println("H ist gleich 0");
        if (T == 0)
        System.out.println("T ist gleich 0");
        else
        System.out.println("Weder H noch T sind 0");
        System.out.println();
    }
}


Frage nun: wie kann ich optimal die Variablen bis zur letzten Methode weiterreichen, und wie kann ich "i", welche in der Methode "Ausgabe" inkrementiert wird, so abspeichern, dass es nach erneutem aufrufen der Methode in der richtigen Größe zur Verfügung steht? Wenn ich es nicht static mache, speichert er den neuen Wert nicht in der Variablen ab.
 
Endless Storm schrieb:
Zur Erinnerung: replace dürfen wir noch nicht verwenden...

Keine der bisher geposteten Antworten verwendet die Methode replace der Klasse String. :)

Zur neuen Aufgabe: werde ich mir jetzt mal durchlesen :)
Evtl. könntest du kurz erklären, wie das Symbolrätsel genau funktioniert bzw. funktionieren soll? Der oben gezeigte Code sieht zumindest auf den ersten Blick stark verbesserungsfähig aus :)
 
Zuletzt bearbeitet:
Also es macht folgendes:
Dieses Programm löst ein Symbolrätsel, indem es Buchstaben in Zahlen umwandelt und die Rechenaufgabe prüft. Dazu werden mit mehreren ineinander verschachtelten Berechnungen alle Lösungen ausgegeben.

Die Berechnung ist folgende:
H E S + T H E = B E S T

Nun prüft man also, ob z.B. H = 1, E = 2 usw, die Rechenaufgabe lösen würde. Logischerweise dürfen zwei Buchstaben nicht dieselbe Zahl sein.
Da dies Aufgabe c) ist, wurden paar Extras eingebaut, zB war in Aufgabe a) H, T und B (die jeweils ersten Buchstaben pro Zeile der Rechenaufgabe) ungleich 0, nun ist auch 0 erlaubt, daher sind auch einige Kommentare entsprechend, wie zB in Zeile 12. Ab Zeile 335 wurde speziell für Aufgabe c) eine Prüfung eingebau, ob die Bedingungen erfüllt sind, die dort lesbar sind als Textausgabe.


Ein Durchlauf des Programms ergibt folgendes Ergebnis, vielleicht fällt das Code-lesen dann leichter:

Code:
Lösungs-Nr.: 1: B = 0, E = 5, H = 2, S = 8, T = 3:
  258
+ 325
_____
 0583
Weder H noch T sind 0

Lösungs-Nr.: 2: B = 0, E = 7, H = 1, S = 9, T = 6:
  179
+ 617
_____
 0796
Weder H noch T sind 0

Lösungs-Nr.: 3: B = 0, E = 8, H = 5, S = 4, T = 2:
  584
+ 258
_____
 0842
Weder H noch T sind 0

Lösungs-Nr.: 4: B = 1, E = 2, H = 4, S = 6, T = 8:
  426
+ 842
_____
 1268
Weder H noch T sind 0
 
Zu Lösung des OP möchte ich keine weiteren Anmerkungen machen. Sieht für mich aus wie eine Art Geheimcode :D

Ich habe stattdessen einmal eine generische Lösung für das genannte Problem programmiert und poste das hier zu einem kleinen Teil. Die Lösung geht insgesamt sicher über den Wissensstand eines Anfängers hinaus, aber vielleicht ist es einmal interessant zu sehen, wie jemand, der schon ein wenig Programmiererfahrung hat, an eine solche Aufgabe herangeht und einige Ideen könnten auch jetzt schon Inspiration liefern.

Grundsätzlich ist der Ansatz weiterhin, die Buchstaben durch Zahlen zu ersetzen und zu ermitteln, wann die Rechenaufgabe ein korrektes Ergebnis ergibt.

Insgesamt verwendet die Lösung elf Klassen. Vier davon sind allerdings automatisch generiert und sollen hier keine Rolle spielen. Was auch schon den größten Unterschied zu einer naiven Implementierung markiert: das Puzzle wird in ein generisches Modell übersetzt, mittels dessen wir nicht nur dieses bestimmte Rätsel lösen können, sondern alle Rätsel dieser Art!

Hierzu kommt mein bevorzugter Parser-Generator zum Einsatz: ANTLR. Die verwendete Grammatik ist eine geringfügig modifizierte Version der Expression-Language aus Kapitel 4 von "The Definitive ANTLR 4 Reference".

Die Hauptklasse schaut so aus:

Code:
@SuppressWarnings("boxing")
public class PuzzleSolver
{
    public static void main(String[] rArgs)
    {
        Collection<Solution> result = new PuzzleSolver().solve("H E S + T H E = B E S T");

        System.out.printf("Found %d solutions%n", result.size());

        for (Solution solution : result)
        {
            System.out.println("-----------------");
            System.out.println(solution);
        }
    }


    public Collection<Solution> solve(String rPuzzle)
    {
        ParseTree tree = parse(rPuzzle);
        LetterMemory memory = new LetterMemory(getLetters(tree));
        PuzzleCalculator calculator = new PuzzleCalculator(memory);

        Collection<Solution> result = new ArrayList<Solution>();

        for (long number = 0, count = memory.getCombinations(); number < count; number++)
        {
            memory.update(number);

            if (calculator.performCalculation(tree).isValid())
            {
                result.add(new Solution(memory.getMappings(), memory.toString(tree)));
            }
        }

        return result;
    }


    private PuzzleParser createParser(String rInput)
    {
        return new PuzzleParser(new CommonTokenStream(
                    new PuzzleLexer(new ANTLRInputStream(rInput))));
    }


    private String[] getLetters(ParseTree rTree)
    {
        return new LetterVisitor().getLetters(rTree);
    }


    private ParseTree parse(String rInput)
    {
        return createParser(rInput).parse();
    }
}


Hat man erst einmal ein solches Modell, kann man damit jede Menge anstellen. So wird im nächsten Schritt ermittelt, wieviele verschiedene Buchstaben im Modell vorhanden sind und ein Objekt erstellt, das dazu dient, die Zuordnung von Buchstaben zu Zahlen zu speichern. Damit haben wir die Eingabe für unseren simplen Rechner. Jetzt können wir ermitteln, ob die Eingabe zu einer Lösung führt.

Was uns zum nächsten großen Unterschied zum Code des OP führt: Es kommen keine verschachtelten Schleifen zum Einsatz, um die verschiedenen Permutationen zu testen. Stattdessen werden die Kombinationen in einem Rutsch ermittelt.

Für jede Kombination wird der Speicher entsprechend aktualisiert (jedem Buchstaben die jeweilige Zahl zugeordnet) und die Berechnung durchgeführt. Ist das Ergebnis valide, werden die Daten abgespeichert. Selbst wenn man keine Ahnung von Programmieren hat, sollte sich das hoffentlich bei Betrachtung des Codes annähernd nachvollziehen lassen.

Die Ausgabe ergibt für mich übrigens 9 mögliche Lösungen. Vielleicht gibt es noch Spezialbedingungen, die mein Code nicht berücksichtigt.

Code:
Found 9 solutions
-----------------
{T=6, E=7, B=0, S=9, H=1}
179 + 617 = 796
-----------------
{T=3, E=5, B=0, S=8, H=2}
258 + 325 = 583
-----------------
{T=0, E=3, B=0, S=7, H=3}
337 + 33 = 370
-----------------
{T=8, E=2, B=1, S=6, H=4}
426 + 842 = 1268
-----------------
{T=2, E=8, B=0, S=4, H=5}
584 + 258 = 842
-----------------
{T=5, E=0, B=1, S=5, H=5}
505 + 550 = 1055
-----------------
{T=7, E=5, B=1, S=2, H=7}
752 + 775 = 1527
-----------------
{T=4, E=3, B=1, S=1, H=8}
831 + 483 = 1314
-----------------
{T=1, E=1, B=1, S=0, H=9}
910 + 191 = 1101
 
Ok, 5 Ergebnisse kannst du wieder abziehen, denn eine Bedingung war, dass die Buchstaben unterschiedliche Zahlen bedeuten und identische Zahlen nicht vorkommen durften. Habe mich erst schon erschrocken warum du soviele hast^^

-> darum habe ich auch soeinen Aufwand betrieben, damit ich Bedingungen einbauen konnte, ob eine Zahl a) schon dran war und b) übersprungen und später neu probiert werden kann wenn ein anderer Buchstabe schon diese Zahl war.

Somit haben wir die gleichen Ergebnisse unter Beachtung der o.g. Bedingung.

Hast du die Codes in der Ausbildung/Studium erlernt, oder alles selbst angeeignet? Ich finde das echt interessant, dass es für dieselbe Aufgabe, schier unendliche Lösungsansätze gibt^^

Wenn ich mir vorstelle, im späteren Arbeitsleben, wenn ich deinen Code nicht kennen würde, müsste ich mir bestimmt wieder einen langen Umweg kreieren um an dasselbe Ergebnis zu kommen...
 
Zurück
Oben