# Ob die Klammer richtig ist...



## Terence86 (11. Dez 2016)

Hi Leute habe ein paar Probleme mit folgender Aufgabe:





Meine Idee war folgende: Scanner initialisieren.. ganze Line einlesen und dann überprüfen durch einen Zähler(Counter) ob die Anzahl der offenen Klammern mit der Anzahl der schließenden übereinstimmt. Fehlen würde mir die Beachtung der Reihenfolge, da zb. "}" + "{"  auch gültige wären und die die Regel wenn sie zb. verschachtelt sind. Müsste ich ja die Positionen notieren wann diese vorkommen und ein Regel festlegen. Die Frage ist auch muss ich mit einem, ich nenns mal "offenen" Scanner (has.Next) das ganze angehen und jedes Token einzeln anschauen (mittels zb. while Schleife), oder wie ich gedacht hatte die ganzen Zeichenketten in einem String speichern und dann überprüfen? Oder vielleicht auch den Eingabe String als Array speichern und nach Klammern durchsuchen?
Was meinte er mit der Hilfsmethode? Die soll mir wenn ich einen gefundene offene Klammer finde, die schließende Klammer finden. Das würde nicht funktionieren wenn ich while (has.next) hätte da die Eingabe noch am laufen wäre. Ich tappe noch im Dunkeln vielleicht hat eine Idee oder weiß einen guten Hinweis.


----------



## Meniskusschaden (11. Dez 2016)

Terence86 hat gesagt.:


> Was meinte er mit der Hilfsmethode? Die soll mir wenn ich einen gefundene offene Klammer finde, die schließende Klammer finden. Das würde nicht funktionieren wenn ich while (has.next) hätte da die Eingabe noch am laufen wäre


Die Hilfsmethode soll die Zeichenketten bis zur nächsten schliessenden Klammer lesen. Wenn das die richtige Klammer ist, soll sie true liefern, andernfalls false. Bei einer öffnenden Klammer muß sie sich selbst mit passenden Parametern aufrufen und geeignet auf das Ergebnis reagieren. Deine ganzen Überlegungen mit Position notieren, Klammeranzahl etc. benötigst du nicht. Die Hilfsmethode ist im Grunde schon die vollständige Lösung.


----------



## Terence86 (11. Dez 2016)

Ah also wird die Eingabe eingelesen bis eine öffnende Klammer kommt, und dann wird in der  "hilfsMethode" weiter gelesen und geprüft ob die richtige schließende Klammer kommt oder nicht. D.h ich lese die Eingabe nicht komplett und speicher sie als String oder Array .. Richtig? Also Zeichenkette für Zeichenkette.


----------



## Meniskusschaden (11. Dez 2016)

Ja, die Methode liest immer nur die Zeichenketten, die zur eigenen Klammerebene gehören.


----------



## Terence86 (11. Dez 2016)

Oha dann habe ich das auch mit der Verschachtelung ja in einem Abwasch?
So grad mal das Beispiel: ... { ... ( ... ) ... } ...       "..." -> Zeichenkette.
Ablauf: ... {  // Öffnende Klammer gefunden
-> Gibt "}" + Scanner weiter an hilfsMethode ->  ... ( .... ) ... } ->  Gefunden. Aber jetzt war doch vorher eine andere geschlossene Klammer, habe ich da grade einen Denkfehler gemacht? Oder läuft das anders ab? Sonst müsste ich doch in der Hilfsmethode noch sagen wenn eine neue geöffnete gefunden wird, das er dann erst diejenige schließende Klammer sucht oder nicht?


----------



## Meniskusschaden (11. Dez 2016)

Bei der runden öffnenden Klammer erfolgt ja wieder ein Aufruf der Hilfsmethode, der für die Zeichen bis zur schliessenden runden Klammer zuständig ist.


----------



## Terence86 (11. Dez 2016)

Danke erstmal mach mir paar Gedanken dazu und formulier den Code dann mal.


----------



## Terence86 (12. Dez 2016)

Mhhh irgendwas stimmt nicht so ganz. Mein Code soweit:

```
public static Boolean pruefeKlammern() {
        Scanner sc = new Scanner(System.in);
      
        while (sc.hasNext()) {
            String eingabe = sc.next();
            if (eingabe.equals("{")) {
                return hilfsMethode(sc, "}");
            }
            if (eingabe.equals("(")) {
                return hilfsMethode(sc, ")");
            }
            if (eingabe.equals("[")) {
                return hilfsMethode(sc, "]");
            }
          
        } sc.close();
        return false;

    }

    private static Boolean hilfsMethode(Scanner sc, String n) {
        String eingabe = sc.next();
        if (eingabe.equals(n)) {
            return true;
        }
        return hilfsMethode(sc, n);

    }
```


----------



## Terence86 (12. Dez 2016)

Update:

```
public static Boolean pruefeKlammern() {
        Scanner sc = new Scanner(System.in);

        while (sc.hasNext()) {
            String eingabe = sc.next();

            if (eingabe.equals("{")) {
                return hilfsMethode(sc, "}");
            }
            if (eingabe.equals("(")) {
                return hilfsMethode(sc, ")");
            }
            if (eingabe.equals("[")) {
                return hilfsMethode(sc, "]");
            }

        }
        return false;

    }

    private static Boolean hilfsMethode(Scanner sc, String n) {
        String eingabe = sc.next();
        if (eingabe.equals(n)) {
            return true;
        }
        else if (eingabe.equals("}") || eingabe.equals(")") || eingabe.equals("]")) {
            return false;
        }
        if (eingabe.equals("{")) {
            return hilfsMethode(sc, "}");
        }
        if (eingabe.equals("(")) {
            return hilfsMethode(sc, ")");
        }
        if (eingabe.equals("[")) {
            return hilfsMethode(sc, "]");
        }
        return hilfsMethode(sc, n);

    }
```


----------



## Meniskusschaden (12. Dez 2016)

Wofür brauchst du denn die pruefeKlammern-Methode? Ich würde die Hilfsmethode direkt aus der main-Methode aufrufen. Da ist bei dir doch irgendwie dieselbe Logik doppelt implementiert.

Ausserdem verarbeitest du in der Hilfsmethode nur eine Zeichenkette. Das würde nur funktionieren, wenn nach einer öffnenden Klammer sofort eine schließende kommt. Es kann aber auch mal etwas dazwischen stehen.

Das:

```
if (eingabe.equals("{")) {
  return hilfsMethode(sc, "}");
}
```
kannst du nicht so machen, denn dann würdest du ja auch dann aus der aktuellen Ebene herausspringen, wenn in der gerade untersuchten tieferen Ebene kein Fehler gefunden wurde. In dem Fall musst du aber noch bis zur passenden Klammer der aktuellen Ebene weiter lesen.


----------



## Terence86 (12. Dez 2016)

Ja das mit der doppelten Implementierung hatte ich auch schon gemacht. Habe nur den Scanner initialisiert da ich den zum Übergeben brauche und dann die hilfsMethode aufgerufen. Ja mein Problem das ich noch zu lösen hatte dachte ich wäre genau das : ... ( ... { ... } .. ) .. , da springt er nach der Geschlossenen raus ohne die letzte Klammer überprüft zu haben.


Meniskusschaden hat gesagt.:


> Ausserdem verarbeitest du in der Hilfsmethode nur eine Zeichenkette.


Meine Klammern als Zeichenketten, oder alle Token von der Eingabe? Dann müsste ich ja anders vorgehen.


Meniskusschaden hat gesagt.:


> Das:
> kannst du nicht so machen, denn dann würdest du ja auch dann aus der aktuellen Ebene herausspringen, wenn in der gerade untersuchten tieferen Ebene kein Fehler gefunden wurde.


Wie realisiere ich den das? Sobald eine neue geöffnete Klammer vorkommt muss ich doch erst diese überprüfen.  Sonst wäre das ja auch richtig ... [ .. (... ] ...) ..


----------



## Xyz1 (12. Dez 2016)

Mal schnell, wie es mit einem Stack funktionieren würd:

```
public static void main(String[] args) throws IOException {
        System.out.println(klammern(" a { b ( c ) d { e [ f ] g ( h ) i } j } k "));
        System.out.println(klammern(" a { b ( c ) d { e{ [ f ] g ( h ) i } j } k "));
    }

    static boolean klammern(String s) {
        LinkedList<String> stack = new LinkedList<>();
        for (char c : s.toCharArray()) {
            String cs = String.valueOf(c);
            if ("{([".contains(cs)) {
                stack.add(cs);
            } else {
                String cs2 = null;
                switch (cs) {
                    case "}":
                        cs2 = "{";
                        break;
                    case ")":
                        cs2 = "(";
                        break;
                    case "]":
                        cs2 = "[";
                        break;
                }
                if (cs2 != null) {
                    if (stack.getLast().equals(cs2)) {
                        stack.removeLast();
                    } else {
                        return false;
                    }
                }
            }
        }
        return stack.isEmpty();
    }
```

IDE ist aber auch nicht dumm und markiert das:


----------



## Meniskusschaden (12. Dez 2016)

Terence86 hat gesagt.:


> Meniskusschaden hat gesagt.:
> 
> 
> > Ausserdem verarbeitest du in der Hilfsmethode nur eine Zeichenkette.
> ...


Die Hilfsmethode verarbeitet alle Zeichenketten bis zur nächsten schliessenden Klammer. Für die Zeichenketten der tieferen Ebenen (inklusive zugehöriger schliessender Klammern) tut sie es, indem sie die Hilfsmethode nochmals aufruft, für die Zeichenketten der eigenen Ebene erledigt sie es selbst.


Terence86 hat gesagt.:


> Meniskusschaden hat gesagt.:
> 
> 
> > Das:
> ...


Indem du abhängig vom Rückgabewert der Hilfsmethode entweder raus springst oder weiter liest.





Terence86 hat gesagt.:


> Sobald eine neue geöffnete Klammer vorkommt muss ich doch erst diese überprüfen. Sonst wäre das ja auch richtig ... [ .. (... ] ...) ..


Das erledigst du durch erneutes Aufrufen der Hilfsmethode.


----------



## Xyz1 (12. Dez 2016)

Mal schnell eine Frage... ich finde die Aufgabe gar nicht so leicht (zu verstehen)... Wenn man den stack oben als Klassen- oder Objektvariable schreiben würd, wäre diese Aufgabe damit dann gelöst?


----------



## Meniskusschaden (12. Dez 2016)

Bin mir nicht ganz sicher, ob die Hinweise der Aufgabenstellung als Tipps oder als Vorgaben zu verstehen sind. Ich glaube eher Letzteres und dann wäre eine rekursive Lösung nötig.


----------



## Xyz1 (12. Dez 2016)

Nagut, recursive method calls bilden aber (quasi) einen Stack ab (JVM internals), wäre nun die Frage, wie man das nun umsetzt.
Also mich verwirrt diese Aufgabe schon etwas. Ich warte einfach mal Lösung(en) ab.


----------



## Terence86 (12. Dez 2016)

Habe das ganze nun so gelöst wurde auch angenommen:

```
public class Eingabe {

    public static Boolean pruefeKlammern() {
        Scanner sc = new Scanner(System.in);

        return hilfsMethode(sc, null);

    }

    private static Boolean hilfsMethode(Scanner sc, String n) {

        while (sc.hasNext()) {

            String eingabe = sc.next();
            if (eingabe.equals(n)) {
                return true;
            }
            if (eingabe.equals("{")) {
                if(!hilfsMethode(sc, "}"))
                        return false;
            }
            if (eingabe.equals("(")) {
                if(!hilfsMethode(sc, ")"))
                    return false;
            }
            if (eingabe.equals("[")) {
                if(!hilfsMethode(sc, "]"))
                    return false;
            }

            if (eingabe.equals("}") || eingabe.equals(")") || eingabe.equals("]")) {
                return false;
            }
            //return hilfsMethode(sc, n);
        }
        if(n==null)
            return true;
        else
        return false;

    }
```

Habe ich was nicht Bedacht? Morgen werden verschiedene Tests noch durchgeführt.(nach Abgabe Termin)


----------



## Meniskusschaden (12. Dez 2016)

Ich finde, das sieht gut aus. Unter dem Leerstring, der im Hinweis zum ursprünglichen Aufruf erwähnt wird, hätte ich allerdings nicht null sondern "" verstanden. Das könnte unter Umständen kritisiert werden.


----------



## Terence86 (12. Dez 2016)

Alles klar. Falls der Nach-Test Fehler zeigt post ich die mal. Falls mal jemand was ähnliches machen muss.


----------



## Terence86 (13. Dez 2016)

Ist schon spät aber habe null durch "" ersetzt, da bekam ich ein Fehler :

```
return hilfsMethode(sc, "");
```
Fehler: 

```
PreTest...

testPruefeKlammern1:
Eingabe von:
--------------------------------
public class Hi {
public static void main ( String [ ] args ) {
System.out.println ( "Hi!" ) ;
}
}
--------------------------------
ueber System.in
FEHLER: zuletzt erwarteter und tatsächlich erhaltener Wert unterscheiden sich
erwartet wurde: true
erhalten wurde: false

testPruefeKlammern2:
OK
testPruefeKlammern3:
OK
testPruefeKlammern4:
OK
testPruefeKlammern5:
OK
testPruefeKlammern6:
OK
testPruefeKlammern7:
OK

...PreTest fehlgeschlagen :-(
```


----------



## Meniskusschaden (13. Dez 2016)

Dann wird wohl doch null erwartet. Den Begriff Leerstring finde ich dafür aber etwas seltsam.


----------

