Java Switch...Case Alternativen?

Ich würde es mir mit bits merken:
Code:
        private const String KEY_objektStart = "objektStart";
        private const String KEY_aussenStart = "aussenStart";
        private const String KEY_innenStart = "innenStart";
        private const String KEY_innenEnde = "innenEnde";
        private const String KEY_aussenEnde = "aussenEnde";
        private const String KEY_objektEnde = "objektEnde";
        private const int KEY_OBJEKTBIT = 1;
        private const int KEY_AUSSENBIT = 2;
        private const int KEY_INNENBIT = 4;

        private static boolean alleStatementsGeschlossen(ArrayList<String> dateiInhalt) {
            int state = 0;
            for (int i = 0; i < dateiInhalt.size(); i++) {
                switch (dateiInhalt.get(i)) {
                    case KEY_objektStart:
                        if (state != 0)
                            return fehlerAusgabe(KEY_objektStart, i);

                        state = KEY_OBJEKTBIT;
                        break;
                    case KEY_aussenStart:
                        if (state != KEY_OBJEKTBIT)
                            return fehlerAusgabe(KEY_aussenStart, i);

                        state |= KEY_AUSSENBIT;
                        break;
                    case KEY_innenStart:
                        if (state != (KEY_OBJEKTBIT | KEY_AUSSENBIT))
                            return fehlerAusgabe(KEY_innenStart , i);

                        state |= KEY_INNENBIT;
                        break;
                    case KEY_innenEnde:
                        if (state != (KEY_OBJEKTBIT | KEY_AUSSENBIT | KEY_INNENBIT))
                            return fehlerAusgabe(KEY_innenEnde , i);

                        state = (KEY_OBJEKTBIT | KEY_AUSSENBIT);
                        break;
                    case KEY_aussenEnde:
                        if (state != (KEY_OBJEKTBIT | KEY_AUSSENBIT))
                            return fehlerAusgabe(KEY_aussenEnde , i);

                        state = KEY_OBJEKTBIT;
                        break;
                    case KEY_objektEnde:
                        if (state != KEY_OBJEKTBIT)
                            return fehlerAusgabe(KEY_objektEnde , i);

                        state = 0;
                        break;
                    default:
                        break;
                }
            }
            return (state == 0);
        }
        
        private static boolean fehlerAusgabe(String strInput, int number) {
            System.out.println("Fehler vor " + strInput + " in Zeile " + number);
            return false;
        }
 
Puh, wird immer komplizierter. Da will ich auch mal :D

Code:
		ArrayList<String[][]> tags = new ArrayList<String[][]>();
		tags.add(new String[][]{{"ObjektStart", "ObjetkEnd"}});
		tags.add(new String[][]{{"AussenStart", "AussenEnd"}});
		tags.add(new String[][]{{"InnenStart", "InnenEnd"}});

		// parse text
		// tags.contains() .... 
		// besser als switch/case, da nicht hard coded und leicht erweiterbar

String[][] tmp;

		for(int i= 0; i < tags.size(); i++){
			  tmp = tags.get(i);
			  System.out.println(tmp[0][0] + " " + tmp[0][1]);
		}
 
Zuletzt bearbeitet:
Für mich schreit das ein bisschen nach einem State Pattern.

Aber wer schreibt schon nen Parser selber... und dann reicht das irgendwann auch nicht mehr, nur zu prüfen ob das File valide ist...
 
Guten morgen! Was eine Schande, dass das, was ich hier zusammengebaut habe quasi nur durch Zufall funktioniert hat. :heul: Wie dem auch sei... Ich würde gerne weiter an dem Problem arbeiten und deshalb danke für die Hilfe! :daumen:

@thecain: Einen Parser selbst schreiben MUSS ich nicht, aber... Erstens bekomme ich die Daten so vorgesetzt und hab keinen Einfluss darauf, d.h. was das Dateiformat anbelangt kann ich nicht mitbestimmen. :( Zweitens: Ich nehm das als Übung gerne mit. Ich bin nicht wirklich gut, möchte mich aber verbessern. Mir ist übrigens durchaus bewusst, dass ich beim Parsen noch andere Parameter habe, die auf Inkonsistenzen geprüft werden müssen, nur das hier ist halt der erste Schritt. ;)

@lynxx: Danke für dein Beispiel; ich werde das Zeitnah mal austesten.

@black90: Vielen Dank für deinen Input; das Ganze sieht vielversprechend aus. Bezüglich (J)DOM: Es wird ja als XML-Werkzeug 'beworben', aber ist man damit auf nicht nur auf XML beschränkt?
 
War jetzt so von dem Problem angetan das ich mal fix eine eigene Lösung implementiert habe.

Leider ohne Stack und case. aber vieleicht hilf dir das als Denk anstoß.

Code:
    private enum State {
        OBJEKT_START("objektStart", "^objektEnde|aussenStart$", false),
        AUSSEN_START("aussenStart", "^aussenEnde|innenStart$", false),
        INNEN_START("innenStart", "^(innenEnde|Daten).*$", false),
        DATEN("Daten", "^Daten.*|innenEnde$", true),
        INNEN_ENDE("innenEnde", "^innenStart|aussenEnde$", false),
        AUSSEN_ENDE("aussenEnde", "^aussenStart|objektEnde$", false),
        OBJEKT_ENDE("objektEnde", "^$", false),
        UNBEKANNT("", "", false);

        private String label;
        private Matcher allowedStates;
        private boolean isData;

        private State(String label, String allowedPattern, boolean isData) {
            this.label = label;
            this.allowedStates = Pattern.compile(allowedPattern).matcher("");
            this.isData = isData;
        }

        public String getLabel() {
            return label;
        }

        public boolean isStateAllowed(State s) {
            return allowedStates.reset(s.getLabel()).matches();
        }

        public Matcher getAllowedStates() {
            return allowedStates;
        }

        public boolean isData() {
            return isData;
        }

        public static State getStateByData(String data) {
            for (State state : values()) {
                if (state.getLabel().equalsIgnoreCase(data.split(" ")[0])) {
                    return state;
                }
            }
            return UNBEKANNT;
        }

    }

    private static final String[] data =
        new String[] { "objektStart", "aussenStart", "innenStart", "Daten A1 A2 A3", "Daten B1 B2 B3", "Daten C1 C2 C3", "innenEnde",
            "aussenEnde", "aussenEnde", "innenStart", "Daten A1 A2 A3", "Daten B1 B2 B3", "Daten C1 C2 C3", "innenEnde", "aussenEnde",
            "objektEnde" };

    public static void main(String[] args) {

        State currentState = null;

        for (String s : data) {
            State nextState = State.getStateByData(s);
            if (currentState == null && State.OBJEKT_START == nextState) {
                currentState = State.OBJEKT_START;
                continue;
            }

            if (currentState.isStateAllowed(nextState)) {
                currentState = nextState;
                if (currentState.isData()) {
                    System.out.println("Daten gefunden: " + currentState.getLabel());
                }
            }
            else {
                throw new IllegalArgumentException("Aktueller Zustand erlaubt folgende Elemente: "
                    + currentState.getAllowedStates().pattern().toString() + " gefunden wurde aber " + s);
            }
        }
    }
 
Zuletzt bearbeitet: (anpassung ermittelung des nächsten zustands)
Die geposteten Lösungen (lynxx & Korialstrasz) sind viel zu kompliziert und funktionieren auch nur bei einfachen Strutkuren.
Sind z.B. mehrere Objekte ineinander verschachtelt, werden diese Lösungen Probleme bekommen, obwohl die Daten valide sind:
Code:
objektStart
   aussenStart              
      objektStart
         aussenStart
            innenStart
               Daten A1 A2 A3
               Daten B1 B2 B3
               Daten C1 C2 C3
            innenEnde
         aussenEnde
      objektEnde
   aussenEnde
objektEnde


black90 hat ja eigentlich schon die beste Lösung genannt: Ein Stack + eine Liste mit den Start/End-tag Paaren.
Das ist flexibel, leicht erweiterbar und performant.


Das Vorgehen ist eigentlich recht einfach. Man geht die Tags Schritt für Schritt durch:
  • Trifft man auf ein öffnendes Element, wirft man es auf den Stack (um die Reihenfolge aller öffnenden Elemente zu speichern)
  • Trifft man auf ein schließendes Element, prüft man ob es zum zuletzt gefundenen öffnendem Element (ganz oben auf dem Stack) passt. Falls es passt --> Element vom Stack entfernen und weitermachen; Falls es nicht passt --> Elemente sind nicht balanciert --> abbrechen
Wenn der gesamte Datensatz erfolgreich durchlaufen wurde und am ende keine öffnenden Elemente auf dem Stack mehr übrig sind (also zu jedem öffnenden auch ein schließendes Element gefunden wurde), dann sind die Elemente balanciert.

Ich hab das ganze mal implementiert:
Code:
static boolean areTagsBalanced(List<String> tags, HashMap<String, String> tagPairs)
{
    Stack<String> openingTags = new Stack<String>();
    HashSet<String> closingTags = new HashSet<String>(tagPairs.values());

    for (String tag : tags)
    {
        tag = tag.trim();

        if (tagPairs.containsKey(tag))
        {
            openingTags.push(tag);
        }
        else if (closingTags.contains(tag))
        {
            if (openingTags.isEmpty()
                    || !tag.equals(tagPairs.get(openingTags.pop())))
            {
                return false;
            }
        }
    }

    return openingTags.isEmpty();
}

Die tagPairs werden in der Form "OpeningTag : ClosingTag" erwartet, also so:
Code:
HashMap<String, String> tagPairs = new HashMap<String, String>();
tagPairs.put("objektStart", "objektEnde");
tagPairs.put("aussenStart", "aussenEnde");
tagPairs.put("innenStart", "innenEnde");
 
Zuletzt bearbeitet: (Formatierung)
Wow, vielen Dank an alle für den ganzen Input!

@Grantig: Sehr interessant, was Du da Implementiert hast. Das werde ich heute abend direkt mal ausprobieren. :)
 
Ich schaue da immer auf Symmetrie. Sind die Tags symmetrisch ab auf den Stack :D

Was performance angeht, da muss man sich die Funktionsweise von Caches und Pages (RAM) ansehen.
Da gibt es auch Verdrängungstrategien, so das wenig benutztes entsorgt wird (hier in der Liste nach hinten geschoben). Häufige Tags wären dann dann immer vorne und die Laufzeit wäre ziemlich gering.

Alternativ ein Baum bauen, da hätte man sowas wie logarithmische Laufzeiten (jede Ebene fällt etwa die Hälfte der Knoten weg). Machen Compiler / Interpreter ähnlich um die Syntax auf Gültigkeit zu überprüfen.
 
Zuletzt bearbeitet:
black90 schrieb:
Was performance angeht, da muss man sich die Funktionsweise von Caches und Pages (RAM) ansehen.
Dir ist schon klar, dass der Limitierende Faktor hier das einlesen der Textdatei ist? Wir reden hier von einer Hand voll Tags - die bleiben ohnehin die ganze Zeit im L1. Und auch wenns statistisch gesehen sicher effizienter ist zuerst die "LowLevel" Tags zu checken kann ich mir nicht vorstellen, dass sich das in der Laufzeit bemerkbar macht.

Davon abgesehen würde mich ernsthaft interessieren, wie in Java chache-freundlicher Code aussieht. Bei C/C++ hab ich meistens ne ziemlich genaue Vorstellung davon, welche Operationen teuer sind und welche Objekte, wie im Speicher liegen. Bei Java fehtl mir da völlig das Gefühl dafür.
 
Grantig schrieb:
Die geposteten Lösungen (lynxx & Korialstrasz) sind viel zu kompliziert und funktionieren auch nur bei einfachen Strutkuren.
Sind z.B. mehrere Objekte ineinander verschachtelt, werden diese Lösungen Probleme bekommen, obwohl die Daten valide sind:
Code:
objektStart
   aussenStart              
      objektStart
         aussenStart
            innenStart
               Daten A1 A2 A3
               Daten B1 B2 B3
               Daten C1 C2 C3
            innenEnde
         aussenEnde
      objektEnde
   aussenEnde
objektEnde

Du hast recht meine Implementierung ist komplexer hat aber den Vorteil das hier die Daten gegen eine Art DTD validiert werden, die Regel habe ich aus den Beispieldaten im ersten Post abgeleitet.

Sollten sich diese Regel ändern so ist es dafür aber einfach diese im Quellcode anzupassen da hier nur das Enum erweitert/verändert werden muss.

Sollte es wirklich so sein das die Daten keinen Regel folgen und sich bei jeder verarbeitung verändern ist ein einfaches Zählen der öffnenden und schließenden Tags einfacher.

@Miuwa: Dafür habe ich bis heute auch noch kein gefühl da dies haupsächlich von der Implementierung der JavaVM (Garbage Collection usw.) abhängt und Java eine Spache ist in der man das, meines Wissens nach, nur bedingt beinflussen kann #WeakReferences.
 
Zuletzt bearbeitet:
Korialstrasz schrieb:
Sollte es wirklich so sein das die Daten keinen Regel folgen und sich bei jeder verarbeitung verändern ist ein einfaches Zählen der öffnenden und schließenden Tags einfacher.
Nein, einfaches Zählen funktioniert nicht, denn dabei würde auch sowas als valid durchgehen:
Code:
objektStart
   aussenEnde
   objektEnde
aussenStart

Korialstrasz schrieb:
Sollten sich diese Regel ändern so ist es dafür aber einfach diese im Quellcode anzupassen da hier nur das Enum erweitert/verändert werden muss.
Na dann versuch mal deine Enum so anzupassen, dass objekt-Blöcke ineinander verschachtelt sein können (so wie z.B. in meinem Beispiel das du zitiert hast) und mach ein diff um zu sehen wieviel du ändern musstest.
 
Moisen! Ich hab mal wieder ein wenig Freizeit und kann mich mit diesem Problem auseinandersetzen. Mir geistert allerdings noch etwas im Kopf herum, dass zwar schon ziemlich von der Ausgangsfrage abweicht, aber ich wollte dafür nicht extra einen neuen Thread aufmachen. Vielleicht kann mir ja trotzdem ein bisschen Input geben.

Es geht um die Art und Weise, wie der Parser aufgerufen wird. Bei mir ist das Ganze zwar schon in zwei Klassen getrennt (eine Klasse öffnet und liest die Datei, eine zweite Klasse dient zum Parsen), aber ist die Umsetzung noch etwas unschön.

Z.B. wird in der einen Klasse zwar die Datei geöffnet und die Exceptions abgedeckt, aber es wird eben auch der Inhalt der Datei mittels Scanner in eine ArrayList<String> gelesen. Ich bin mir nicht sicher, ob letzteres nicht eigentlich im Parser passieren sollte, nur dann ist (zumindest bei mir) die reine Trennung von File-Handling und Parsen wieder flöten. Außerdem ist es jetzt zwangsläufig darauf ausgerichtet, nur Daten in dem angegebenen Format zu lesen; aber was ist wenn ich später noch andere Formate lesen will und einen zweiten Parser hinzufügen muss? Kennt vielleicht jemand ein paar Beispiele oder kann aus dem Nähkästchen plaudern, wie man das reine Handling von Dateien (und den darauf folgenden Aufruf eines Parsers) am besten macht?

MfG
Vulpecula
 
Java API:
http://docs.oracle.com/javase/7/docs/api/java/io/FileReader.html

Schau dir die Vererbungshierarchie an. Ein Reader, der generell definiert wie es funktioniert (abstract) wird dann vom FileReader erweitert damit er auch aus Files lesen kann. Daraus kannst ja dann XMLReader oder sonst was basteln. Die Gemeinsamkeit liegt darin, dass immer Chars gelesen werden, du weißt bei anderen Formaten nur nicht welche Muster du darin suchen musst.

z.b.

1. Speicherklasse, z.B. Baum oder LinkedList (ist ein Baum mit 1 Kindknoten)
2. Parserklasse, legt im Baum Nodes an
3. FileHandler Klasse, die den üblichen Kram mit I/O Exceptions macht und dem Parser ein Objekt mit Daten übergibt wenn erfolgreich
4. ReaderKlasse, die durch Baumknoten iteriert und Daten sucht

Von Array/ ArrayList rate ich ab, du weißt nicht wie groß es werden wird. Eine ArrayList hat begrenzten Array Speicher, wird der überschritten wird intern ein neues, größeres Array erstellt und der ganze Kram umkopiert. Array Elemente im Speicher liegen immer beieinander. LinkedList Elemente zeigen nur auf das nächste Elemet, irgendwo im Speicher.

Dann kannst das Zeug ineinander stacken, ähnlich BufferedReader: new Speicherklasse(New Parserklasse(new FileHandlerKlasse))).Den Parser kannst ja auch noch weiter aufdröseln, Grundfunktionalität in oberste Parserklasse (readTag() readText() ...), Subklassen spezialisieren immer weiter was dann mit dem Tag gemacht wird , was dann letztendlich die Format Unterscheidung darstellt, d.h. die untersten Klassen die vom Parser erben wissen was die Tags darstellen und handeln dann, z.B. Text auslesen und im Baum als Text-Node speichern.

Beispiel DOM:
http://docs.oracle.com/javase/7/docs/api/org/w3c/dom/package-summary.html

Da gibt es praktisch einen Baum mit verschiedenen Knoten für Element, Text, Entity usw.
Die Parserklasse samt Subklassen legt dann so Knoten im Baum an.
Diesen Baum könntest dann mit ReaderKlasse auslesen und gezielt Tag / Text usw. suchen

Wenn dann richtig :p
 
Zuletzt bearbeitet:
Morgen!

Okay, ich versuche das mal nachzuvollziehen.

black90 schrieb:
1. Speicherklasse, z.B. Baum oder LinkedList (ist ein Baum mit 1 Kindknoten)
2. Parserklasse, legt im Baum Nodes an
3. FileHandler Klasse, die den üblichen Kram mit I/O Exceptions macht und dem Parser ein Objekt mit Daten übergibt wenn erfolgreich
4. ReaderKlasse, die durch Baumknoten iteriert und Daten sucht

D.h. ich würde die Datei bzw. Dateipfad + Namen übergeben:

Code:
new Speicherklasse(New Parserklasse(new FileHandlerKlasse("DateipfadUndNameAlsString")));

Wenn ich das jetzt von Innen nach Außen durchgehe:

  1. Der FileHandler liest die Datei, allerdings noch nicht die Daten, sondern übergibt die Datei als Objekt? D.h. der FileHandler müsste auch, je nach Dateityp - den richtigen Parser wählen?
  2. Die Parserklasse interpretiert die gelesenen Daten und erstellt Objekte, die die Speicherklasse aufnimmt.
  3. Es wird eine Instanz der Speicherklasse erzeugt. Heißt das, dass hier lediglich die Datenstruktur bzw. die Collection festgelegt wird? (Momentan benutze ich einen Vector, der einfach nur die vom Parser erzeugten Objekte aufnimmt.)


Um Nochmal auf das Dateiformat zu sprechen zu kommen: Die Regeln, nach denen die Datei erzeugt wird, bleiben immer gleich:

Code:
objektStart  Kommentarstring
    	aussenStart  int1
        		innenStart
            Daten  wertA  wertB  wertC
            // evtl. noch mehr Zeilen mit Daten
        		innenEnde
    	aussenEnde
    	aussenStart  int2
        		innenStart
            Daten  wertD  wertE  wertF
            // evtl. noch mehr Zeilen mit Daten
        		innenEnde
    	aussenEnde
    // ...usw...
objektEnde

  • objektStart bzw. objektEnde gibt es je Datei nur ein einziges Mal. Evtl. gibt es nach objektStart in der selben Zeile noch einen Kommentar, aber das ist kein muss. Delimiter ist hier ein Whitespace.
  • Die Blöcke bestehend aus aussenStart, innenStart, Daten, innenEnde, aussenEnde können beliebig oft vorkommen und deren Anzahl kann auch relativ groß werden (>500.000 ist keine Seltenheit).
  • In der selben Zeile wie aussenStart steht immer ein Integer-Wert. Delimiter ist hier auch hier wieder ein ein Whitespace.
  • In der Zeile mit dem Daten-Tag stehen immer drei durch Whitespaces getrennte Werte, die verschiedene Formate haben können (Integer oder Floating-Points). Es können bis zu drei Zeilen mit Daten-Tags aufeinander Folgen, was in der Regel auch der Fall ist, aber nicht sein muss.

Das sind die Regeln, nach der die Datei erstellt werden muss und wird. Alles andere wird als Fehler verworfen.

Mal abgesehen von einigen anderen Bedingungen, die für die Konsistenz der Datei erfüllt sein müssen, will ich erstmal ein das Problem der geöffneten und geschlossenen Tags in den Griff kriegen. Das heißt, dass ich mir um die Daten selbst noch nicht sonderlich viel Gedanken mache. ;)
 
Zuletzt bearbeitet:
Dann ist es ja einfach...und du hast etliche Möglichkeiten.
Hier mal drei...

1. Zeilenweise lesen und Strings suchen, dann mit Positionen arbeiten und Daten speichern
2. REGEX benutzen um das Zeug zwischen Tags zu fischen

Starthilfe für REGEX falls gewünscht:
http://stackoverflow.com/questions/6020384/create-array-of-regex-matches

Wenn du den Kram zwischen den Tags hast, musst ihn irgendwie speichern.

Normal wäre ein Baum ideal, aber ich weiß nicht ob du sowas programmieren kannst ? Aber ich versuchs mal halbwegs zu erklären unter Benutzung üblicher Java Funktionlität, das spart dir add(), remove() usw. selbst implementieren zu müssen da du auf den Kram der LinkedList zugreifen kannst :D

Es gibt eine Klasse mit zwei Feldern, nennen wir die Klasse mal "Data".
Diese Klasse hat ein Feld "int num", sowie ein Feld das "LinkedList<Data> data ". Dann noch Methoden um darin etwas einzufügen. Der Konstruktor legt leere Listen an. Damit wäre die Datenhaltung fertig. Nun weiter in der main()

Hier hast du eine LinkedList<Data> a = new LinkedList<Data>() für Außenbereiche.
Dein Parser kommt, findet den ersten Außenbereich. Nun legt er ein "Data" Objekt an, nennen wir es "aussen". Die Nummer des Außenbereichs speichert er in aussen.num .

Nun parst er innerhalb des Außenbereichs und sucht nach einem Innenbereich. Wenn er einen findet, legt er ein neues Data Objekt an, nennen wir es "innen" und merkt sich wieder den Namen im String.

Nun parst er im Innenbereich nach Datensätzen und für jeden Datensatz legt er erneut ein Data Objekt in innen.data an. Wenn es keine Datensätze mehr gibt, dann füge der aussen.data Liste einen Innenbereich an (aussen.data.add(innen) falls die felder public sind, oder halt über getter/setter Methoden gehen).

Wiederhole mit nächstem Innenbereich...., wenn keiner mehr vorhanden, füge den Außenbereich (aussen) in die Liste der Außenbereiche (a) ein.

Weiter mit nächstem Außenbereich...bis keine rmehr vorhanden. ENDE.

------
Somit hast du eine verschachtelte Liste wo du über Außenbereiche iterieren kannst. Jedes Objekt hat ja die Nummer drin stehen, sowie eine Liste mit Data Objekten die Innenbereiche darstellen, über die du wieder iterieren kannst. Darin sind noch mal Data Objekte die Datensätze darstellen. Das könntest ewig weiter verschachteln. Wäre sogar recht performant....

Würdes also ein tripple for brauchen:
for außenbereiche
...for innenbereiche
......for datensätze

Würde mich wundern wenn du irgendwas verstanden hättest. Damit hatten mehr als die Hälfte der Informatik Studenten ziemlichen Ärger .. :)
 
Zuletzt bearbeitet:
Wenn ich eine Klasse namens "Data" habe, die eine Linked List von Typ <Data> enhält, würde die Klasse dann nicht quasi eine Instanz von sich selbst erzeugen?
 
Nicht im Konstruktor, das würde in die Hose gehen (Endlosrekursion, es sei denn, du steuerst das über Parameter). Siehe auch "Composite Pattern".
 
Hallo nochmal! Mein Problem hat sich etwas geändert - genauer gesagt das Dateiformat. Tatsächlich war das einlesen der Daten bisher nur ein Vorgeplänkel und jetzt soll ein "reales" Datenformat eingelesen werden: Stereolithograpie-Dateien.

Nach wie vor gibt es die Dateien im ASCII-Format vor und diese sind immer nach dem selben Schema aufgebaut:

Code:
solid [NAME]
    facet normal [NX] [NY] [NZ]
        outer loop 
            vertex [P1X] [P1Y] [P1Z]
            vertex [P2X] [P2Y] [P2Z]
            vertex [P3X] [P3Y] [P3Z]
        endloop
    endfacet
    ... + (theoretisch) unendlich viele facet-endfacet-Blöcke.
endsolid [NAME]

Ich kann die Daten einlesen, die Verktorargumente (P1X,...) auf Validität prüfen, prüfen ob jeder Vektor genau drei Argumente besitzt und so weiter, aber ich breche mir gerade fürchterlich einen dabei ab, zu prüfen, ob die einzelnen Tags in der richtigen Reihenfolge sind.

Momentan sieht mein Code so aus:

Code:
private static boolean stlStructureIsValid ()
{
    Map<String, String> parents = new HashMap<String, String>();
    parents.put(SOLID, null);
    parents.put(FACET, SOLID);
    parents.put(OUTER, FACET);
		
    Stack<String> openingTags = new Stack<String>();
    String actualParent;

    for (String content : fileContent)
    {
        if (parents.containsKey(content))
        {
            if(openingTags.isEmpty())
            {
                openingTags.push(content);
                continue;
            }
            else
            {
                actualParent = openingTags.peek();
                if (!actualParent.equals(parents.get(content)))
                {
                    return false;
                }
                openingTags.push(content);
            }
        }
    }
    return true; 
}

Das ganze funktioniert genau so lange, bis er den ersten Block abgeschlossen hat, danach ist Schluss. Es liegt wohl daran, dass beim neuen Block "FACET" gelesen wird, aber "OUTER" ganz oben auf dem Stack, was ja kein Parent von FACET sein darf. Momentan weiß ich nicht so recht, wie ich von hier weiterkomme, aber vielleicht hat jemand von Euch noch eine Idee, die mir einen Schubser in die richtige Richtung geben kann.

Grüße - Vulpecula

P.S.: Da das Dateiformat ziemlich strickt ist, reicht es, die Reihenfolge der öffnenden Tags zu prüfen. Das Balancing der Tags (ob alle Tags korrekt geschlossen wurden) werde ich dann danach (von Grantigs Beispiel abgeleitet) implementieren.
 
Zuletzt bearbeitet:
Da es nun ein bekanntest Format ist, würde ich auf einen bereits existierenden Parser/Reader zurückgreifen
 
@Vulpecula
Du entfernst nie etwas von deinem Stack. Du solltest aber für jedes closing-tag das entsprechende opening-tag vom Stack entfernen, womit du dann exakt bei meiner Lösung landest.

Wenn dus selbst machen willst, wäre es vermutlich am besten einfach meine Lösung zu erweitern: Jedesmal wenn ein opening-tag gefunden wird, musst du prüfen, ob das momentane opening-tag (stack.peek()) als parent erlaubt ist.

Wenn du 2 Methoden dafür schreibst musst du ja zweimal über die komplette Datei iterieren.


Meine Empfehlung an dich: das was thecain sagt.

org.j3d.loaders.stl.STLFileReader
 

Ähnliche Themen

W
  • Gesperrt
  • Frage
2 3
Antworten
45
Aufrufe
2.642
Antworten
10
Aufrufe
760
Zurück
Oben