Stack mit bestimmter Aufgabe

Heinrich500

Bekanntes Mitglied
Hallo,
ich will mittels eines Stacks eine Klasse implementieren, die die Korrektheit eines Klammerausdrucks überprüft. Das Programm bekomt dabei als Programmargument den Pfad einer Textdatei übergeben. Das erste Problem ist jetzt schon, wie ich auf diese Textdatei dann zugreifen könnte. Hier mein Versuch:
Java:
public class Klammern {

    public static boolean rightBrackets(String s) {
        Stack<Character> stack  = new Stack<Character>();
        for(int i = 0; i < s.length(); i++) {
            char c = s.charAt(i);
            if(c == '[' || c == '(' || c == '{' ) {     
                stack.push(c);
            } else if(c == ']') {
                if(stack.empty() || stack.pop() != '[') {
                    return false;
                }
            } else if(c == ')') {
                if(stack.empty() || stack.pop() != '(') {
                    return false;
                }           
            } else if(c == '}') {
                if(stack.empty() || stack.pop() != '{') {
                    return false;
                }
            }

        }
        return stack.empty();
    }

    
    
    
    
    public static void main(String[] args) {
        String path = args[0];
        File CP_file = new File(path);
        
        //Wie übergebe ich meiner Methode jetzt die Textdatei?
      
      
    }
 
Also dann so:
Java:
           String path = args[0];
        File CP_file = new File(path);
        FileReader fr = new FileReader(CP_file);
Das funktioniert leider nicht und ich wüsste auch nicht, wie ich das in einen String umwandeln könnte?
 
Ich verstehe leider nicht alle Anweisungen mihe. Würde es vllt auch so gehen:
Java:
 String path = args[0];
       File CP_file = new File(path);
       BufferedReader in = new BufferedReader (new FileReader (CP_file) );
       String ausgabe=in.readLine()    ;
 
Ja, damit liest Du eine Zeile ein, wobei Du in dem Fall try-with-resources verwenden solltest, damit der Reader auch wieder geschlossen wird:
Java:
try(BufferedReader in = new BufferedReader(new FileReader (CP_file))) {
    String line = in.readLine();
    verarbeite(line);
}
Um alle Zeilen der Datei zu behandeln, packt man das in eine Schleife:
Java:
try(BufferedReader in = new BufferedReader(new FileReader (CP_file))) {
    String line;
    while ((line = in.readLine()) != null) {
        verarbeite(line);
    }
}
Natürlich kann man erst alle Zeilen einlesen, z. B. in eine Liste und dann über die Liste iterieren:
Java:
List<String> lines = new ArrayList<>();
try(BufferedReader in = new BufferedReader(new FileReader (CP_file))) {
    String line;
    while ((line = in.readLine()) != null) {
        lines.add(zeile);
    }
}

for (String line : lines) {
    verarbeite(line);
}
Und den ersten Teil kann man mit Hilfe von java.nio.file.Files kurz schreiben:
Java:
List<String> lines = java.nio.file.Files.readAllLines(CP_file.toPath());

for (String line : lines) {
    verarbeite(line);
}
Alles klar?
 
List<String> lines = new ArrayList<>(); try(BufferedReader in = new BufferedReader(new FileReader (CP_file))) { String line; while ((line = in.readLine()) != null) { lines.add(zeile); } } for (String line : lines) { verarbeite(line); }
Alles klar. Das zeile müsste dann doch line sein oder?

Wie könnte ich mit meinem Stack die Positionen des zusammengehörigen Klammerpaares ausgeben?
 
Das zeile müsste dann doch line sein oder?
Oops, ja. Übersehen. Ich hatte das zuerst mit zeile geschrieben und dann auf line umbenannt, damit es besser zum Code von vorhin passt 🙂

Wie könnte ich mit meinem Stack die Positionen des zusammengehörigen Klammerpaares ausgeben?
Indem Du Dir eine Klasse schreibst, deren Objekte je ein Zeichen inkl. dessen Position im String darstellen.
 
Ich habe eine Methode vorgegeben, die folgendes macht:
Die Methode erhält als Parameter die Zeile und Spalte der öffnenden undschließenden Klammern sowie die Klammern selbst als Zeichen. Dies führt zu eine runseren Testfällen genügenden Ausgabe wie z. B.:Matching brackets: ’[’ at line 1, column 10 and ’]’ at line 1, column 11

Dann muss ich mir ja auch noch merken, in welcher Zeile die Klammer steht.
Wie merke ich mir die Zeile und Spalte.
Kannst du mir da noch einen Tipp geben?
 
Ja dürfen sie:
Z.b gibt es folgende Ausgabe:
Matching·brackets:·'{'·at·line·1,·column·16·and·'}'·at·line·3,·column·1
Also kann ich mein obiges Programm nicht verwenden?
Könntest du vllt den Anfang von deiner Idee zeigen bitte?
Vllt würde ich es dann besser verstehen.
 
Du willst Dir die Zeile und die Spalte eines Zeichens sowie das Zeichen selbst merken:
Java:
class CharacterPosition {
    public final int row;
    public final int col;
    public final char character;

    public CharacterPosition(int row, int col, char character) {
        this.row = row;
        this.col = col;
        this.character = character;
    }
}

Statt einfach nur ein '{' auf den Stack zu legen, verwendest Du also ein Objekt vom Typ CharacterPosition. Die Zeilen und Spalten kannst Du in den Schleifen mitzählen.
 
Aso vielen Dank🙂
Was mir gerade noch leider erst jetzt auffällt, muss ich alles in einer Klasse machen.
Geht es theoretisch die class CharacterPosition mit in die Klasse Klammer einzubetten?
 
Naja, Du hast die Zeilen ja jetzt in einer Liste und die ist "nummeriert":
Java:
for (int row = 0, n = lines.size(); row < n; row++) {
    String line = lines.get(row);
}
row ist der Zeilenindex, die Zeilennummer (für die Ausgabe) wäre dann row+1.
 
Wie meinst Du das? Du gehst ja Zeile für Zeile und jede Zeile Zeichen für Zeichen durch. Wenn Du auf eine öffnende Klammer stößt, kennst Du also Zeile (row), Spalte (col) und das Zeichen (ch) mit der öffnenden Klammer. Dann legst Du ein new CharacterPosition(row, col, ch) auf den Stack.

Stößt Du auf eine schließende Klammer, kennst Du wieder die Zeile (row), Spalte (col) und das Zeichen (ch) mit der schließenden Klammer. Auf dem Stack liegt ggf. die CharacterPosition der öffnenden Klammer.
 
Ok ja jetzt habe ich es. Man geht ja hier die Zeilen entlang:
Java:
for (String line : lines) {
            verarbeite(line);
        }

Das Problem ist, dass ich die Methoden mit Objekten nicht ausführen kann, z.b ist push so implementiert:
Java:
public void push(T t) {
        
        StackNode<T> tmp=new StackNode<T>(t);
        tmp.next=topElement;
        topElement=tmp;
        counter++;
    }

Wie kann man das dann machen?
 
Ich weiß nicht, was Du hier betreibst:
Java:
import java.util.*;

public class Klammern {
    static class CharacterPosition {
        public final int row;
        public final int col;
        public final char character;

        public CharacterPosition(int row, int col, char character) {
            this.row = row;
            this.col = col;
            this.character = character;
        }
    }

    public static void process(List<String> lines) {
        Stack<CharacterPosition> positions = new Stack<>();
        for (int row = 0, n = lines.size(); row < n; row++) {
            String line = lines.get(row);
            for (int col = 0, m = line.length(); col < m; col++) {
                char ch = line.charAt(col);
                if (ch == '(') {
                    positions.push(new CharacterPosition(row, col, ch));
                }
            }
        }

        while (!positions.isEmpty()) {
            CharacterPosition pos = positions.pop();
            System.out.printf("%c gefunden in Zeile %d, Spalte %d\n", pos.character, pos.row+1, pos.col+1);
        }
    }

    public static void main(String[] args) {
        List<String> lines = Arrays.asList(
            "Dies ist ein Beispiel (wirklich), das zeigt, ",
            "dass Positionen (Zeilen und Spalten) von Klammern ",
            "ausgegeben werden");
        Klammern.process(lines);
    }
}
 
Ich bin selber etwas verwirrt. Vielen Dank für dein Programm. Jetzt muss ich noch einbauen, dass Klammerpaare erkannt werden. Solte man dazu die while-Schleife entfernen und nach dem
Java:
 if(ch=='('))
folgendes einbauen:
Java:
else if(c == ')') {
                if(!stack.empty() && stack.pop() == '(') {
                printMatch(row, col, ch)
                }
 
Java:
 public static void process(List<String> lines) {
        Stack<CharacterPosition> positions = new Stack<>();
        for (int row = 0;row <  lines.size(); row++) {
            String line = lines.get(row);
            for (int col = 0, m = line.length(); col < m; col++) {
                char ch = line.charAt(col);
                if (ch == '(' || ch == '[' || ch == '{' ) {
                    positions.push(new CharacterPosition(row, col, ch));
                }
                else if(ch == ']') {
                    if(!positions.empty() || positions.pop() != '[') {
                       Printall(row,col,ch);
                    }
                }
                else if(ch == ')') {
                    if(!positions.empty() || positions.pop() != '(') {
                        Printall(row,col,ch);
                    }           
                }
                else if(ch == '}') {
                    if(!positions.empty() || positions.pop() != '{') {
                        Printall(row,col,ch);
                    }
                }
            }   
        }     
        

      
    }

Das Problem ist, dass
Java:
positions.pop() != '[')
nicht funktioniert. Folgender Fehler:
Incompatible operand types Klammer.CharacterPosition and char
Wie kann ich das lösen?
 
positions.pop() liefert ein Objekt vom Typ CharacterPosition. Daher musst Du mit den Methoden/Attributen dieses Typs arbeiten:
Java:
CharacterPosition p = positions.pop();
if (p.character == '}') {
...
}
 
Ist nicht so schön wsl, aber wäre das dann insgesamt korrekt:
Java:
  if (ch == '(' || ch == '[' || ch == '{' ) {
                    positions.push(new CharacterPosition(row, col, ch));
                }
              
                else if(ch == ']') {
                    CharacterPosition p = positions.pop();
                    if(!positions.empty() && p.character == ']') {
                       Printall(row,col,ch);
                    }
                }
                else if(ch == ')') {
                    haracterPosition p = positions.pop();
                    if(!positions.empty() && p.character == ')') {
                        Printall(row,col,ch);
                    }           
                }
                else if(ch == '}') {
                    CharacterPosition p = positions.pop();
                    if(!positions.empty()&& p.character == '}') {
                        Printall(row,col,ch);
                    }
 
Oh man. Tut mir leid. Also dann wäre es doch beispielhaft so:
Java:
 else if(ch == ']') {
                    
                    if(!positions.empty()) {
                        CharacterPosition p = positions.pop();
                        if(p.character == ']') {
                            Printall(row,col,ch);
                        }   
                    }
                }
 
Danke🙂 In meiner main-Methode läuft das einlesen dann so:
Java:
String path = args[0];
        File CP_file = new File(path);
        BufferedReader in = new BufferedReader(new FileReader (CP_file));
             List<String> lines = new ArrayList<String>();
             String line;
             while ((line = in.readLine()) != null) {
                    lines.add(line);
             }
             CheckBracketExpressions.process(lines);
Wäre das ok. Ich bin mir nicht ganz sicher
 
Vielen Dank.
Ich habe ja immer die printall-Methode verwendet. Jedoch brauche ich nicht nur 3 sondern 6 Parameter. Ich habe dann diese wie folgt implementiert:
Java:
 public static void printMatch(int rowL, int columnL, char leftBracket, int rowR, int columnR, char rightBracket) {
        System.out.println( "Matching brackets: '" + leftBracket+ "' at line " + rowL + ", column " + columnL
                + " and '" + rightBracket + "' at line " + rowR + ", column " + columnR );
    }

Wie füge ich die am besten nun in das Programm ein?
 
Jetzt schau Dir mal Deinen Code an:
Java:
                else if(ch == ']') {
                        CharacterPosition p = positions.pop();
                        if(p.character == ']') {
                            Printall(row,col,ch);
                        }
Wie Du siehst, hast Du: row, col, ch und... p. Dabei sind row, col, ch die Zeile, Spalte und das Zeichen der schließenden Klammer. In p findest Du die Angaben für die linke Klammer: p.col, p.row, p.character.

Da fällt mir auf, dass mir vorhin ein Fehler unterlaufen ist: die if-Bedingung muss natürlich die öffnende Klammer prüfen:
Java:
                else if(ch == ']') {
                        CharacterPosition p = positions.pop();
                        if(p.character == '[') {
                            Printall(row,col,ch);
                        }
 
Vielen Dank. Es hat geklappt🙂
Jetzt stimmen nur nicht die Indizes der Zeilen und Spalten.
Java:
lse if(ch == ']') {
                    
                    if(!positions.empty()) {
                        CharacterPosition p = positions.pop();
                        if(p.character == '[') {
                            printMatch(p.row,p.col,p.character, row, col,ch);
                        }   
                    }
                }
Müsste ich nicht row, col jeweils um 1 erhöhen?
 
Ja, row und col sind Indizes (beginnend bei 0). Für die Ausgabe der Spalten- und Zeilennummern musst du jeweils um 1 erhöhen: printMatch(p.row+1, p.col+1, p.character, row+1, col+1, ch);
 
Es geht. Ich habe
if(p.character == ']') nicht verändert. Jetzt funktioniert es.
Es soll noch eine Fehlerbehandlung durchgeführt werden:
printUnmatchedClosingBracket: Erhält als Parameter die Zeile und Spalte der gefundenen, schließenden Klammer, welche eingelesen wurde, obwohl der Stack leer ist.
Das habe ich dann wie folgt, umgesetzt:
Java:
else if(ch == ']') {
                   
                    if(!positions.empty()) {
                        CharacterPosition p = positions.pop();
                        if(p.character == '[') {
                            printMatch(p.row+1,p.col+1,p.character, row+1, col+1,ch);
                        }  
                    }
                    else {
                        printUnmatchedClosingBracket(row+1, col+1,ch);
                    }
                }
Jedoch scheint das nicht richtig zu sein, Wenn ich in den else Zweig komme, dann ist doch der Stack leer?
 
Es gibt zwei Fälle:
1. der Stack enthält z. B. ein '(', wenn Du auf ein ']' triffst: unmatched 🙂
2. der Stack ist leer, wenn Du auf eine schließende Klammer triffst.
 
Und: es gibt noch einen weiteren Fall. Wenn alle Zeilen verarbeitet wurden und der Stack nicht leer ist, dann hast Du öffnende Klammern, die nicht geschlossen wurden.
 
1. der Stack enthält z. B. ein '(', wenn Du auf ein ']' triffst: unmatched
Ich muss das ja am Anfang z.b von
Java:
if else ch==']
prüfen.
Java:
else if(ch == ']') {
                    CharacterPosition x = positions.top();
                    if(x.character!='[') printUnmatchedClosingBracket(row+1, col+1,ch);
                    if(!positions.empty()) {
                        CharacterPosition p = positions.pop();
                        if(p.character == '[') {
                            printMatch(p.row+1,p.col+1,p.character, row+1, col+1,ch);
                        }   
                    }
                    else {
                        printUnmatchedClosingBracket(row+1, col+1,ch);
                    }
                }
Etwas redudant, was sagst du?
 
Dann so:
Java:
lse if(ch == ']') {
                    
                    if(!positions.empty()) {
                        CharacterPosition p = positions.pop();
                        if(p.character == '[') {
                            printMatch(p.row+1,p.col+1,p.character, row+1, col+1,ch);
                        }
                        else {
                            printUnmatchedClosingBracket(row+1, col+1,ch);
                        }
                    }
                    else {
                        printUnmatchedClosingBracket(row+1, col+1,ch);
                    }
                }
Den letzen Fall weis ich nicht genau, wo ich den unterbringen soll,
 
Nach der Schleife:
Java:
while (!positions.empty()) {
    CharacterPosition p = positions.pop();
    printUnmatchedOpeningBracket(p.row+1, p.col+1, p.character);
}
 
Funktioniert leider nicht ganz: Siehst du den Fehler?
Java:
public static void process(List<String> lines) {
        Stack<CharacterPosition> positions = new Stack<>();
        for (int row = 0;row <  lines.size(); row++) {
            String line = lines.get(row);
            
            for (int col = 0; col < line.length(); col++) {
                    char ch = line.charAt(col);
                
                
                if (ch == '(' || ch == '[' || ch == '{' ) {
                    positions.push(new CharacterPosition(row, col, ch));
                }
              
                else if(ch == ']') {
                    
                    if(!positions.empty()) {
                        CharacterPosition p = positions.pop();
                        if(p.character == '[') {
                            Main.printMatch(p.row+1,p.col+1,p.character, row+1, col+1,ch);
                        }
                        else {
                            Main.printUnmatchedClosingBracket(row+1, col+1,ch);
                        }
                    }
                    else {
                        Main.printUnmatchedClosingBracket(row+1, col+1,ch);
                    }
                }
                else if(ch == ')') {
                     if(!positions.empty()) {
                         CharacterPosition p = positions.pop();
                         if(p.character == '(') {
                             Main.printMatch(p.row+1,p.col+1,p.character, row+1, col+1,ch);
                         }
                         else {
                            Main.printUnmatchedClosingBracket(row+1, col+1,ch);
                        }
                     }
                     else {
                         Main.printUnmatchedClosingBracket(row+1, col+1,ch);
                     }
                }
                else if(ch == '}') {
                     if(!positions.empty()) {
                         CharacterPosition p = positions.pop();
                         if(p.character == '{') {
                             Main.printMatch(p.row+1,p.col+1,p.character, row+1, col+1,ch);
                         }
                         else {
                            Main.printUnmatchedClosingBracket(row+1, col+1,ch);
                        }
                     }
                     else {
                         Main.printUnmatchedClosingBracket(row+1, col+1,ch);
                     }
                }   
            } 
        }
        while (!positions.empty()) {
        CharacterPosition p = positions.pop();
        Main.printUnmatchedOpeningBracket(p.row+1, p.col+1, p.character);
        }
    }
 
Vielen Dank.
Ich habe ja immer die printall-Methode verwendet. Jedoch brauche ich nicht nur 3 sondern 6 Parameter. Ich habe dann diese wie folgt implementiert:
Eigentlich genügen 2 Parameter.
Java:
public static void printMatch(CharacterPosition pOpen, CharacterPosition pClose) {
        System.out.println( "Matching brackets: '" + pOpen.character + "' at line " + pOpen.row + ", column " + pOpen.col
                + " and '" + pClose.character + "' at line " + pClose.row + ", column " + pClose.col );
    }
 

Neue Themen


Zurück
Oben