Stringverarbeitung

deggit_biber

Aktives Mitglied
Hallo,

wir lernen gerade Java in der Schule und beschäftigen uns gerade mit der Stringverarbeitung.

Wir sollen einen String in dieser Art analysieren

#_!!!_++_**** // Dieser Code entspricht dem Empfänger: Etage 3, Flur 2, Zimmer 4

# -> Beginn der Nachricht
_ -> trennt die Teilbereiche der Nachricht
! -> Anzahl der Etagen
+ -> Anzahl Flur
* -> Anzahl Zimmer

Die Strings können verschieden sein, es ist auch möglich, dass ein String falsch ist. Aber es dürfen maximal 5mal !, 4mal + und 10mal * vorkommen.

Jetzt sollen wir eine Methode schreiben, die den String untersucht und ein boolean zurückgibt, ob der String korrekt oder nicht korrekt ist.

Folgende Methoden der Klasse String dürfen wir dazu nutzen:
s.length()
s.indexOf(t)
s.indexOf(t, anfang)
s.lastIndexOf(t)
s.charAt(stelle)
s.substring(anfang, ende)
s.substring(anfang)
s.toLowerCase()
s.toUpperCase()
s.trim()
s.equals(t)
s.replace(t, z)

Der Anfang ist auch noch recht einfach

Code:
public boolean GueltigkeitsPruefung(String Wert)
    {
        if (Wert.charAt(0) == '#')
        {
            if (Wert.charAt(1) == '_')
            {
                if
            }
        }
    }

Jetzt müsste auf ! prüfen, ich weiß auch, dass ein ! am Platzt des 2ten Stringindex sein muss, damit die Eingabe stimmt, aber ob jetzt 1 oder 5 ! folgen, dies weiß ich ja nicht. Also wie kann ich auf das nächste _ prüfen, wenn ich nicht weiß an welcher Stelle es vorkommt? Habt ihr da vielleicht einen kleinen Denkanstoß für mich?


Vielen vielen lieben Dank
Deggit
 

Joose

Top Contributor
Mittels Schleife kannst du jedes einzelne Zeichen durchgehen.
Du musst dann nur prüfen ist das der Anfang einer Nachricht? Folgt darauf ein Trennzeichen, wieviele "!" folgen dann? Folgt darauf ein Trennzeichen? ......

Java:
for(int i = 0; i < wert.length(); i++) {
   // der code
}
Du wirst natürlich auch außerhalb der Schleife die eine oder andere Hilfsvariable brauchen.
 
X

Xyz1

Gast
Geile Aufgabe... ich bin dabei.

Java:
    private static int[] etageFlurZimmer(String string) {
        int[] rueckgabe = new int[3];
        Pattern pattern = Pattern.compile("^\\#\\_(\\!+)\\_(\\++)\\_(\\*+)");
        Matcher matcher = pattern.matcher(string);
        if (matcher.find()) {
            for (int i = 0; i < rueckgabe.length; i++) {
                rueckgabe[i] = matcher.group(i + 1).length();
            }
        }
        System.out.println("Etage "+rueckgabe[0]+", Flur "+rueckgabe[1]+", Zimmer "+rueckgabe[2]);
        return rueckgabe;
    }

etageFlurZimmer("#_!!!_++_****");
 
K

kneitzel

Gast
Hmm. Zu welcher Aufgabe soll das die Lösung sein? Es wurden weder die erlaubten Mittel eingesetzt noch gibt die Funktion das gewünschte Resultat zurück.
Und zwischen einem String mit 0. Etage, 0. Flur und 0. Zimmer und einem ungültigen String gibt es bei Dir auch keinen Unterschied.
 
X

Xyz1

Gast
Hmm. Zu welcher Aufgabe soll das die Lösung sein? Es wurden weder die erlaubten Mittel eingesetzt noch gibt die Funktion das gewünschte Resultat zurück.
Und zwischen einem String mit 0. Etage, 0. Flur und 0. Zimmer und einem ungültigen String gibt es bei Dir auch keinen Unterschied.

1. das stimmt, ich hatte zu schnell an einen Regulären Ausdruck gedacht, das ist natürlich suboptimal ;)
2. ich dachte, die Nummerierung beginnt nachfolgend mit 1
3. alle Arrays, in denen ein Wert 0 ist (also Tief), sind ungueltig ;)
4. danke für deinen Kommentar
 

deggit_biber

Aktives Mitglied
Hallo,
Danke für eure Anregungen
@Joose: Das mit der Schleife ist mir klar, danke dir aber für den Hinweis

@DerWissende:
könntest du mir das mit den .compile, .matcher, . group einmal erklären, sind bestimmt Methoden der Klasse String, oder?

Ich habe mir auch noch ein paar Gedanken gemacht. Und zwar weiß ich jetzt, wie ich die letzten Stellen von !, + oder * bekomme

LetzteStelleAusrufezeichen = eingabe.lastIndexOf('!');
LetzteStellePlus = eingabe.lastIndexOf('+');
LetzteStelleSternchen = eingabe.lastIndexOf('*');

Das klappt auch schon einmal, z.B. gebe ich als Eingabe #_!!!_+++_***** ein, dann bekomme ich wenn ich mit dir Variablen ansehen

LetzteStelleAusrufezeichen = 4
LetzteStellePlus = 8
LetzteStelleSternchen = 14
 
X

Xyz1

Gast
@DerWissende:
könntest du mir das mit den .compile, .matcher, . group einmal erklären, sind bestimmt Methoden der Klasse String, oder?

Nein, so meinte ich das "leider" nicht, das war eine illegale Lösung von mir...
Java:
    private static boolean gueltig(String string) {
        if (!string.startsWith("#_")) {
            return false;
        }
        int i = 1;
        if (string.charAt(i) != '_') {
            return false;
        }
        i++;
        while (string.charAt(i) == '!') {
            i++;
        }
        // ...
        if (i < string.length()) {
            // ...
        }
        return true;
    }

So dürftest du das schreiben.
 

Joose

Top Contributor
Ich habe mir auch noch ein paar Gedanken gemacht. Und zwar weiß ich jetzt, wie ich die letzten Stellen von !, + oder * bekomme

Wenn du dazu noch die ersten vorkommen des Zeichen findest dann könnte man sich die Länge ja ausrechnen.
Hier die Dokumentation zu der Methode "indexOf": https://docs.oracle.com/javase/7/docs/api/java/lang/String.html#indexOf(java.lang.String)

Bei dieser Methode musst du aber vorher kontrollieren ob der String gültig aufgebaut ist ;)
Bei anderen Methoden kann man die Gültikeit während der Verarbeitung prüfen.
 
K

kneitzel

Gast
Also ich sehe mehrere Möglichkeiten, wie man heran gehen könnte:
a) Man kann den String Zeichen für Zeichen durchgehen. Das würde dann in etwa einem endlichen Automat entsprechen und so würde ich das dann ggf. auch implementieren.
b) Man könnte den String einfach aufteilen. Trenner ist der _ und ich Teile den String so in 4 Teile auf:
1. Teil muss dann das Startzeichen sein.
2. - 3. Teil muss dann jeweils das bestimmte Zeichen sein, dass dann gezählt wird.

Sowohl a) als auch b) lassen sich recht einfach implementieren, so man sich die einzelnen Teilaufgaben auf einem Zettel klar macht.

Bezüglich der Lösung von DerWissende: Das ist eine Lösung, wie ich sie evtl. auch aufbauen würde. Da werden aber reguläre Ausdrücke verwendet und das ist Dir nicht gestattet, so dass diese Lösungsidee nicht in Frage kommt.

Konrad
 

deggit_biber

Aktives Mitglied
Hallo,
danke für eure Hilfe! Ich werde mich gleich mal hinsetzen und programmieren. Poste dann entweder meine Lösung oder meinen Fortschritt mit dem eventuellen Problem ;-)
viele grüße
 

Blender3D

Top Contributor
So könnte man es auch probieren!
Java:
public class MsgReader {
    private static final int[] cmds_max = { 10, 4, 5 }; // maximum allowed
    private int[] cmds_count = new int[cmds_max.length]; // counts commands
    private boolean correct = false; // used by getter methods
    public static final int ROOM_ID = 0;
    public static final int CORRIDOR_ID = 1;
    public static final int FLOOR_ID = 2;
    public static final char INIT = '#';
    public static final char SEPERATOR = '_';
    public static final char ROOM = '*';
    public static final char CORRIDOR = '+';
    public static final char FLOOR = '!';

    /**
     * Counts up specified command.
     *
     * @param id
     *            Command's id
     * @param current_cmd
     *            Checks if there has been a separator before each command.
     * @return True if added command doesn't exceed allowed range.
     */
    private boolean addCmd(int id, int current_cmd) {
        if (current_cmd != SEPERATOR && current_cmd != id)
            return false;
        cmds_count[id]++;
        return cmds_count[id] > cmds_max[id] ? false : true;
    }

    public boolean isCorrect(String test) {
        correct = false;
        if (test == null || test.length() < 1)
            return false;
        test = test.trim();
        if (test.charAt(0) != INIT)
            return false;
        int current_cmd = INIT;
        for (int i = 1; i < test.length(); i++) {
            char c = test.charAt(i);
            switch (c) {
            case ROOM:
                if (!addCmd(ROOM_ID, current_cmd))
                    return false;
                current_cmd = ROOM_ID;
                continue;
            case CORRIDOR:
                if (!addCmd(CORRIDOR_ID, current_cmd))
                    return false;
                current_cmd = CORRIDOR_ID;
                continue;
            case FLOOR:
                if (!addCmd(FLOOR_ID, current_cmd))
                    return false;
                current_cmd = FLOOR_ID;
                continue;
            case SEPERATOR:
                current_cmd = SEPERATOR;
                continue;
            default:
                return false;
            }
        }
        correct = true;
        return true;
    }

    public int getNrOfRooms(int id) throws IllegalStateException, IndexOutOfBoundsException {
        if (!correct)
            throw new IllegalStateException("tested string' s format is illegal");
        return cmds_count[id];
    }
}
 
Zuletzt bearbeitet von einem Moderator:

Blender3D

Top Contributor
Fehler!!

Code:
public boolean isCorrect(String test) {
cmds_count = new int[cmds_max.length];
...
Obiger Code sollte hier Counting arry erstellen. da bei dem nächsten Aufruf von isCorrect nicht bei 0 gestartet wird!
 
X

Xyz1

Gast
Hier sind meine 2 Lösungen der ersten Teilaufgabe:
Java:
    private static boolean gueltig(String string) {
        if (!string.startsWith("#_")) {
            return false;
        }
        int i = 1;
        if (string.charAt(i) != '_') {
            return false;
        }
        i++;
        while (string.charAt(i) == '!') {
            i++;
        }
        if (string.charAt(i) != '_') {
            return false;
        }
        i++;
        while (string.charAt(i) == '+') {
            i++;
        }
        if (string.charAt(i) != '_') {
            return false;
        }
        i++;
        while (i < string.length() && string.charAt(i) == '*') {
            i++;
        }
        if (i < string.length()) {
            return false;
        }
        return true;
    }

    private static boolean gueltig2(String string) {
        String pruefen = "!+*";
        if (!string.startsWith("#_")) {
            return false;
        }
        int i = 1;
        for (char c : pruefen.toCharArray()) {
            if (i == string.length() || string.charAt(i) != '_') {
                return false;
            }
            i++;
            while (i < string.length() && string.charAt(i) == c) {
                i++;
            }
        }
        return i == string.length();
    }

der Rest dürfte doch jetzt nicht mehr schwer sein. Natürlich bilden wir nicht RegEx nach.
 
K

kneitzel

Gast
Das ist schon eine sehr schöne Lösung.

Ich würde die Prüfung mit der Länge des Strings in jeden Check mit einbauen, damit es keine IndexOutOfBoundsException gibt.

Und die Anzahl der jeweiligen Zeichen ist noch in den while-Schleifen zu zählen.
 
K

kneitzel

Gast
Da wir jetzt schon eine beinahe Lösung haben, die für die Schule die Aufgabe löst, erlaube ich mir, hier einmal meine Lösung zu posten, die objektorientiert ist und streng genommen die Logik von DerWissender implementiert. Nur eben doppelten Code entfernt und den Code in Klassen geschoben.
Ich habe hier halt einen endlichen Automaten gesehen mit mehreren Stati. Diese Stati laufen komplett linear, so dass die manuelle Prüfung halt so in if Anweisungen und while schleifen umsetzbar war. Das wird aber bei komplizierteren endlichen Automaten deutlich schwerer. Und wir haben halt "doppelten" Code.

Der Anfang ist dann das Auslesen des Strings. Das ist hier im Code durch das ständige charAt und der Variablen i gemacht. Das habe ich einfach einmal in eine Klasse CharacterSource geschoben:
Java:
package de.kneitzel.homework;

/**
* CharacterSource for a stream of Characters
*/
public class CharacterSource {
    private String sourceString;
    private int position;

    /**
     * Creates a new instance of CharacterSource.
     * @param source Source for all characters.
     */
    public CharacterSource(String source) {
        sourceString = source;
        position = 0;
    }

    /**
     * Get the next character.
     * @return the next Character of the source.
     * @throws IndexOutOfBoundsException When no more characters are available, an IndexOutofBoundsException is thrown.
     */
    public char getNext() {
        return sourceString.charAt(position++);
    }

    /**
     * Checks if another character is available or not.
     * @return true if another character is available else false.
     */
    public boolean hasNext() {
        return position < sourceString.length();
    }
}

Nun haben wir ja die einzelnen Stati. Diese zeichnen sich durch zwei Dinge aus:
a) Wir benötigen einen Zähler
b) es gibt - abhängig vom nächsten Zeichen, einen neuen Status. Also Statusübergänge.

Das habe ich dann wie folgt umgesetzt:
Java:
package de.kneitzel.homework;

import java.util.HashMap;

/**
* A State of our finite state machine
*/
public class State {
    private int numberOfCalls = 0;
    private HashMap<Character, State> stateTransitions = new HashMap<>();

    /**
     * Get the counter how often this state was reached.
     * @return Number this state was reached
     */
    public int getNumberOfCalls() {
        return numberOfCalls;
    }

    /**
     * Add a state transition
     * @param character character for this state transition
     * @param newState new state which is reached when the given character is received
     */
    public void addStateTransition(Character character, State newState) {
        stateTransitions.put(character, newState);
    }

    /**
     * Executes this state.
     *
     * This will get the next character of the source and return the new state.
     *
     * @param source Source to get the character from.
     * @return the new state or null if a transition wasn't possible.
     * @throws IndexOutOfBoundsException if no more characters could be read from the source.
     */
    public State execute(CharacterSource source) {
        numberOfCalls++;
        Character nextChar = source.getNext();
        return stateTransitions.get(nextChar);
    }
}

Nun brauchen wir noch den endlichen Automat. Der ist relativ trivial zu bauen:
- wir haben einen Anfangs-Zustand.
- wie haben eine Menge gültiger Endzustände
- Wir haben eine Funktion, die diesen Automaten ausführt.

Damit bin ich jetzt zu folgender Lösung gekommen:
Java:
package de.kneitzel.homework;

import java.util.HashSet;
import java.util.Set;

/**
* A finite state machine
*/
public class FiniteStateMachine {
    private State startState;
    private Set<State> endStates = new HashSet<>();

    /**
     * Sets the start state.
     * @param startState State in which the system starts.
     */
    public void setStartState(State startState) {
        this.startState = startState;
    }

    /**
     * Adds an end state.
     * @param endState State in which the system starts.
     */
    public void addEndState(State endState) {
        endStates.add(endState);
    }

    /**
     * Executes the finite state machine
     * @param source Input source to use for the state machine
     * @return true if it was an success else false
     */
    public boolean execute(CharacterSource source) {
        State currentState = startState;
        while (currentState != null && source.hasNext()) {
            currentState = currentState.execute(source);
        }

        if (currentState == null)
            return false;

        return endStates.contains(currentState);
    }
}

Diese Code können wir nun natürlich für unser Problem benutzen:
Java:
package de.kneitzel.homework;

/**
* Program that solves the given homework to check a string.
*/
public class Program {
    public static void main(String[] args) {

        // The characters we want to check in our finite state machine
        CharacterSource source = new CharacterSource("#_!!!!_++_****");

        // First we define all the states that we need
        State start = new State();
        State split = new State();
        State floor = new State();
        State corridor = new State();
        State room = new State();

        // Now we add the state transitions
        start.addStateTransition('#', split);
        split.addStateTransition('_', floor);
        floor.addStateTransition('!', floor);
        floor.addStateTransition('_', corridor);
        corridor.addStateTransition('+', corridor);
        corridor.addStateTransition('_', room);
        room.addStateTransition('*', room);

        // Now we use a finite state machine to execute these states with the source
        FiniteStateMachine machine = new FiniteStateMachine();
        machine.setStartState(start);
        machine.addEndState(room);
        boolean result = machine.execute(source);
        if (!result) {
            System.out.println("Unable to get to an end state - source was not valid!");
            return;
        }

        int floors = floor.getNumberOfCalls() - 1;
        int corridors = corridor.getNumberOfCalls() - 1;
        int rooms = room.getNumberOfCalls() - 1;

        if (floors > 5 || corridors > 4 || rooms > 10) {
            System.out.println("The number of floors, corridors or rooms was to big!");
            return;
        }

        System.out.println("Successfully parsed the input:");
        System.out.println("Etagen: " + floors);
        System.out.println("Flure: " + corridors);
        System.out.println("Räume: " + rooms);
    }
}

Noch ein kleiner Hinweis: Ich habe hier jetzt alles Problembezogen entwickelt. Dies ist explizit KEINE Referenzimplementation eines endlichen Automaten, wie er in der Informatik gelehrt wird!

Die Anzahl der Zeilen ist nun deutlich größer geworden, was für dieses einfache Problem evtl. unnötig gewesen wäre aber spätestens wenn Verzweigungen oder komplexere Rekursionen erlaubt sind, wird es in einer einfachen Funktion extrem unübersichtlich.
Und dieser Code ist nun deutlich einfacher anzupassen und auch für andere (ähnliche) Probleme wiederverwendbar.

Und ich denke, dass so eine Lösung hier nicht als Hausaufgaben machen gilt, da die objektorientierte Lösung jenseits des aktuellen Schulwissens der Klasse sein dürfte ...

Konrad
 
X

Xyz1

Gast
DEA?

Ich find' meines immer noch toll:
Java:
    private static int[] etageFlurZimmer(String string) {
        int[] rueckgabe = new int[3];
        Pattern pattern = Pattern.compile("^\\#\\_(\\!+)\\_(\\++)\\_(\\*+)");
        Matcher matcher = pattern.matcher(string);
        if (matcher.find()) {
            for (int i = 0; i < rueckgabe.length; i++) {
                rueckgabe[i] = matcher.group(i + 1).length();
            }
        }
        System.out.println("Etage " + rueckgabe[0] + ", Flur " + rueckgabe[1] + ", Zimmer " + rueckgabe[2]);
        return rueckgabe;
    }

    private static boolean gueltig(String string) {
        int[] feld = new int[]{5, 4, 10};
        int[] rueckgabe = etageFlurZimmer(string);
        for (int i = 0; i < feld.length; i++) {
            if (rueckgabe[i] < 1 || rueckgabe[i] > feld[i]) {
                return false;
            }
        }
        return true;
    }

        System.out.println(gueltig("#_!!!_++_****"));
        System.out.println(gueltig("##_!!!_++_****"));
        System.out.println(gueltig("#_!!!_++_*****"));
        System.out.println(gueltig("_!!!_++_****"));
        System.out.println(gueltig("#_!!!_++_*"));
        System.out.println(gueltig("#_!!!__****"));
        System.out.println(gueltig("#_!_+_*_*"));
        // noch mehr Testfälle

Es dürfte natürlich auch null zurückgegeben werden, wenn der string nicht geparst werden konnte. So ist es ein ungültiger string. Aber das ist nicht gewollt/gewünscht manchmal.

Auch hab ich in dem RegEx kein * verwendet, für mich ergibt eine Nummerierung mit 0 beginnend keinen Sinn, Mathem. sehen das anders.

Tatsächlich hatte ich einen PathProcessor vor nicht all zu langer Zeit selber geschrieben, aber das ist... eh... "der Aufgabenstellung nicht angemessen".

Was will ich eigentlich sagen? Wenn nicht angegeben ist, ob ein Zimmer usw. Nummer 0 haben darf (00 wc :D ), dann hat der Anforderungsanalytiker bei der Anforderungsanalyse gepfuscht.
 
K

kneitzel

Gast
Also die Lösung ist ja auch nicht schlecht. Bei so String-Problemen ist das wohl auch in der Softwareentwicklung der übliche weg.

Da könnte man sich jetzt nur fragen, in wie weit du die einfachste Lösung gefunden hast - die wäre ggf., die Mengenbeschränkung im regulären Ausdruck mit zu verpacken (also {..} statt +) und so nur noch zu prüfen, ob es passt oder nicht. Aber das ist dann reine Klugscheißerei, denn letzten Endes wird ja doch auch die Anzahl benötigt.

Lediglich die Aufgabenstellung untersagt halt leider die Lösung mit regulärem Ausdruck. Aber ebenso würde ich behaupten, dass der Lehrer auch keine Lösung wie die von mir vorgebrachte im Sinn hatte.

Konrad
 

Blender3D

Top Contributor
private static boolean gueltig(String string) {
if (!string.startsWith("#_")) {
return false;
}
int i = 1;
if (string.charAt(i) != '_') {
return false;
}
i++;
while (string.charAt(i) == '!') {
i++;
}
if (string.charAt(i) != '_') {
return false;
}
i++;
while (string.charAt(i) == '+') {
i++;
}
if (string.charAt(i) != '_') {
return false;
}
i++;
while (i < string.length() && string.charAt(i) == '*') {
i++;
}
if (i < string.length()) {
return false;
}
return true;
}
Funktioniert nicht z.B. bei "#_!!_***_++"
 

Blender3D

Top Contributor
# -> Beginn der Nachricht
_ -> trennt die Teilbereiche der Nachricht
! -> Anzahl der Etagen
+ -> Anzahl Flur
* -> Anzahl Zimmer

Die Strings können verschieden sein, es ist auch möglich, dass ein String falsch ist. Aber es dürfen maximal 5mal !, 4mal + und 10mal * vorkommen.
gültige Strings:
#_***_!!_++
#_!!_*_!_++
...
nicht gültige Strings:
_***_!!! --> # fehlt
#_!!!*** --> kein _ zwischen !*
usw.
 
K

kneitzel

Gast
Ok, dann habe ich die Aufgabe nicht richtig verstanden. Da müsste man dann die Status-Übergänge neu definieren.

Da ist dann die Lösung von mir relativ schön, da der Code universell geschrieben wurde.

Die Übergänge muss man sich nur einmal deutlich machen, damit dann klar ist, was erlaubt ist:
# => _
_ => !, * und +
! => ! und _
* => * und _
+ => + und _

Gültige Endstati sind !, * und +

Und dabei ist mir jetzt auch aufgefallen, dass sich auch noch ein anderer Fehler eingeschlichen hat - so wurde das execute auf dem letzten Zeichen nicht mehr ausgeführt, wodurch eine Zahl falsch war. Dadurch musste ich noch etwas mehr umschreiben.

State hat nun eine Trennung zwischen execute und nextState. Und die CharacterSource wird nun nur von der FiniteStateMachine behandelt.

Die geänderten Klassen sind nun:
Java:
package de.kneitzel.homework;

import java.util.HashMap;

/**
* A State of our finite state machine
*/
public class State {
    private int numberOfCalls = 0;
    private HashMap<Character, State> stateTransitions = new HashMap<>();

    /**
     * Get the counter how often this state was reached.
     * @return Number this state was reached
     */
    public int getNumberOfCalls() {
        return numberOfCalls;
    }

    /**
     * Add a state transition
     * @param character character for this state transition
     * @param newState new state which is reached when the given character is received
     */
    public void addStateTransition(Character character, State newState) {
        stateTransitions.put(character, newState);
    }

    /**
     * Executes this state.
     */
    public void execute() {
        numberOfCalls++;
    }

    /**
     * Gets the next State.
     * @param character
     * @return The next State or null if not found.
     */
    public State nextState(Character character) {
        return stateTransitions.get(character);
    }
}

Java:
package de.kneitzel.homework;

import java.util.HashSet;
import java.util.Set;

/**
* A finite state machine
*/
public class FiniteStateMachine {
    private State startState;
    private Set<State> endStates = new HashSet<>();

    /**
     * Sets the start state.
     * @param startState State in which the system starts.
     */
    public void setStartState(State startState) {
        this.startState = startState;
    }

    /**
     * Adds an end state.
     * @param endState State in which the system starts.
     */
    public void addEndState(State endState) {
        endStates.add(endState);
    }

    /**
     * Executes the finite state machine
     * @param source Input source to use for the state machine
     * @return true if it was an success else false
     */
    public boolean execute(CharacterSource source) {
        State currentState = startState;
        while (currentState != null) {
            currentState.execute();

            // Check if we are at the end.
            if (!source.hasNext())
                return endStates.contains(currentState);

            currentState = currentState.nextState(source.getNext());
        }

        // there was no next state for an character
        return false;
    }
}

Java:
package de.kneitzel.homework;

/**
* Program that solves the given homework to check a string.
*/
public class Program {
    public static void main(String[] args) {

        // The characters we want to check in our finite state machine
        CharacterSource source = new CharacterSource("#_!!!!_++_****");

        // First we define all the states that we need
        State start = new State();
        State startSign = new State();
        State split = new State();
        State floor = new State();
        State corridor = new State();
        State room = new State();

        // Now we add the state transitions
        start.addStateTransition('#', startSign);
        startSign.addStateTransition('_', split);
        split.addStateTransition('!', floor);
        split.addStateTransition('+', corridor);
        split.addStateTransition('*', room);
        floor.addStateTransition('!', floor);
        floor.addStateTransition('_', split);
        corridor.addStateTransition('+', corridor);
        corridor.addStateTransition('_', split);
        room.addStateTransition('*', room);
        room.addStateTransition('_', split);

        // Now we use a finite state machine to execute these states with the source
        FiniteStateMachine machine = new FiniteStateMachine();
        machine.setStartState(start);
        machine.addEndState(corridor);
        machine.addEndState(floor);
        machine.addEndState(room);
        boolean result = machine.execute(source);
        if (!result) {
            System.out.println("Unable to get to an end state - source was not valid!");
            return;
        }

        int floors = floor.getNumberOfCalls();
        int corridors = corridor.getNumberOfCalls();
        int rooms = room.getNumberOfCalls();

        if (floors > 5 || corridors > 4 || rooms > 10) {
            System.out.println("The number of floors, corridors or rooms was to big!");
            return;
        }

        System.out.println("Successfully parsed the input:");
        System.out.println("Etagen: " + floors);
        System.out.println("Flure: " + corridors);
        System.out.println("Räume: " + rooms);
    }
}

Das dürfte dann jetzt eine funktionierende Lösung sein.
 

Blender3D

Top Contributor
Hier eine meine korrigierte Lösung.;)
Code:
/**
* Parses a string for commands. (ROOM -> *),(COORIDOR -> *) and (FLOOR -> *).
* The command's appearance is counted.
*
* @see #isCorrect(String)
* @see #getNrOfFoundCmd(int)
* @author Blender3D
*
*/
public class MsgReader {
    private static final int[] cmds_max = { 10, 4, 5 }; // maximum allowed
    private int[] cmds_count = null; // counts commands
    private boolean correct = false; // used by getter methods
    public static final int ROOM_ID = 0;
    public static final int CORRIDOR_ID = 1;
    public static final int FLOOR_ID = 2;
    public static final char INIT = '#';
    public static final char SEPERATOR = '_';
    public static final char ROOM = '*';
    public static final char CORRIDOR = '+';
    public static final char FLOOR = '!';

    /**
     * Counts up specified command.
     *
     * @param id
     *            Command's id
     * @param current_cmd
     *            Checks if there has been a separator before each command.
     * @return True if added command doesn't exceed allowed range.
     */
    private boolean addCmd(int id, int current_cmd) {
        if (current_cmd != SEPERATOR && current_cmd != id)
            return false;
        cmds_count[id]++;
        return cmds_count[id] > cmds_max[id] ? false : true;
    }

    /**
     * [# -> _], [_ -> *,!,+], [* -> *,_],[! -> !,_],[+ -> +,_]
     *
     * @param test
     *            String to be tested.
     * @return True if string follows preceding rules.
     */
    public boolean isCorrect(String test) {
        correct = false;
        if (test == null || test.length() < 1)
            return false;
        test = test.trim();
        int lenght = test.length();
        if (test.charAt(0) != INIT || lenght < 3)
            return false;
        cmds_count = new int[cmds_max.length];
        int current_cmd = INIT;
        for (int i = 1; i < lenght; i++) {
            char c = test.charAt(i);
            switch (c) {
            case ROOM:
                if (!addCmd(ROOM_ID, current_cmd))
                    return false;
                current_cmd = ROOM_ID;
                continue;
            case CORRIDOR:
                if (!addCmd(CORRIDOR_ID, current_cmd))
                    return false;
                current_cmd = CORRIDOR_ID;
                continue;
            case FLOOR:
                if (!addCmd(FLOOR_ID, current_cmd))
                    return false;
                current_cmd = FLOOR_ID;
                continue;
            case SEPERATOR:
                if (current_cmd == SEPERATOR)
                    return false;
                current_cmd = SEPERATOR;
                continue;
            default:
                return false;
            }
        }
        correct = true;
        return true;
    }

    /**
     * @param id
     *            Command's id.
     * @return Command's Number of appearance.
     * @throws IllegalStateException
     *             If parsed String was invalid.
     * @throws IndexOutOfBoundsException
     *             If command's id was invalid.
     */
    public int getNrOfFoundCmd(int id) throws IllegalStateException, IndexOutOfBoundsException {
        if (!correct)
            throw new IllegalStateException("tested string' s format is illegal");
        return cmds_count[id];
    }
}
 

deggit_biber

Aktives Mitglied
Hallo,
so ich hatte leider recht viel zu tun und konnte mich erst jetzt wieder an die Arbeit machen. Ich konnte das Problem jetzt auch alleine lösen, würde aber gerne eure Meinung hören. Da ich bestimmt noch viel verbessern kann.

Hier meine Lösung:
Java:
public boolean pruefung()
    {
        boolean startZeichen = false;
        boolean ersterUnterstrich = false;
        boolean zweiterUnterstrich  = false;
        boolean dritterUnterstrich = false;
        boolean ausrufezeichenAbfrage = false;
        boolean plusAbfrage = false;
        boolean sternchenAbfrage = false;
        boolean komplettePruefung = false;
      
        ersteStelleAusrufezeichen = eingabe.indexOf('!');
        ersteStellePlus = eingabe.indexOf('+');
        ersteStelleSternchen = eingabe.indexOf('*');
      
        letzteStelleAusrufezeichen = eingabe.lastIndexOf('!');
        letzteStellePlus = eingabe.lastIndexOf('+');
        letzteStelleSternchen = eingabe.lastIndexOf('*');
      
        //Teilstrings auslesen
        ausrufezeichen = eingabe.substring(2, (letzteStelleAusrufezeichen + 1));
        plus = eingabe.substring(letzteStelleAusrufezeichen +2,  letzteStellePlus +1);
        sternchen = eingabe.substring(letzteStellePlus +2,  letzteStelleSternchen +1);
      
        //Gültigkeit von # testen
        if (eingabe.charAt(0) == '#')
        { 
            startZeichen = true;    
        }
        else
        {
            return false;
        }
      
        //Gültigkeit des ersten _ testen
        if (eingabe.charAt(1) == '_')
        { 
            ersterUnterstrich = true;    
        }
        else
        {
            return false;
        }

        //Gültigkeit des zweiten _ testen
        if (eingabe.charAt(letzteStelleAusrufezeichen + 1) == '_')
        { 
            zweiterUnterstrich = true;    
        }
        else
        {
            return false;
        }
      
        //Gültigkeit des dritten _ testen
        if (eingabe.charAt(letzteStellePlus + 1) == '_')
        { 
            dritterUnterstrich = true;    
        }
        else
        {
            return false;
        }
      
        //Gültigkeit von ! testen
        if (ausrufezeichen.length() < 5)
        { 
            //Überprüfen, ob alle chars '!' sind, Wenn nicht false ausgeben
            for (int i=0; i < ausrufezeichen.length(); i++)
            {
                if (ausrufezeichen.charAt(i) != '!')
                {
                    return false;
                }
                else
                {
                    ausrufezeichenAbfrage = true;
                }
            }
        }
      
        //Gültigkeit von + testen              
        if (plus.length() < 4)
        { 
            for (int j=0; j < plus.length(); j++)
            {
                if (plus.charAt(j) != '+')
                {
                    return false;
                }
                else
                {
                    plusAbfrage = true;
                }
            }
        }
      
        //Gültigkeit von * testen              
        if (sternchen.length() < 9)
        { 
            for (int w=0; w < sternchen.length(); w++)
            {
                if (sternchen.charAt(w) != '*')
                {
                    return false;
                }
                else
                {
                    sternchenAbfrage = true;
                }
            }
        }              
      
        //komplette Gültigkeitsprüfung
        if (startZeichen == true && ersterUnterstrich == true && zweiterUnterstrich == true && dritterUnterstrich == true && ausrufezeichenAbfrage == true && plusAbfrage == true && sternchenAbfrage == true)
        {
            komplettePruefung = true;
        }
      
        return komplettePruefung;
    }
}

was meint ihr? vielen lieben Danke!!!!
 
Zuletzt bearbeitet von einem Moderator:

Joose

Top Contributor
Alternative Lösungen wurden hier ja schon zu genüge gepostet ;)

Zu deiner Lösung:

Bei den Vergleichen kannst du dir das "== true" sparen
Statt
Java:
if (startZeichen == true && ersterUnterstrich == true && zweiterUnterstrich == true && dritterUnterstrich == true && ausrufezeichenAbfrage == true && plusAbfrage == true && sternchenAbfrage == true)
einfach
Java:
if (startZeichen && ersterUnterstrich && zweiterUnterstrich && dritterUnterstrich && ausrufezeichenAbfrage && plusAbfrage && sternchenAbfrage)
Erklärung: Die if-Bedingung erwartet einen boolean Wert. Deine Variablen selbst sind schon boolean Werte, diese extra nochmal zu vergleichen ist unnötig. Wenn du auf "== false" prüfen willst verwende ein "!" vor dem boolean Wert.

Du kannst dir eigentlich die ganzen boolean Werte sparen ;)
Sobald du einen fehlerhaften Eingabestring findest schreibst du "return false;". Sprich wenn du nie zu einem "return false;" kommst war der Eingabestring gültig und alle Prüfungen haben funktioniert. Daher kannst du am Ende einfach "return true;" schreiben.
Dadurch würden die if-Blöcke leer bleiben, da dass aber nicht gerade schön ausschaut kann man die Bedingung negieren und den Inhalt des else-Block in den if-Block schreiben.

Für die einzelnen Zeichen könntest du Konstanten festlegen, dann musst du für ein anderes Zeichen nur an einer Stelle etwas ändern.

Und was fehlt ist eine Überprüfung ob die Werte für "ersteStelle*" und "letzteStelle*" gültig sind. Was passiert bei deinem Code wenn du gar kein "!" oder "*" oder "+" im Eingabestring hast?

Außerdem fehlen else-Blöcke für den Fall das zuviele Etagen, Flüre oder Zimmer angegeben wurden.

Java:
private static final char BEGINN = '#';
private static final char TRENNER = '_';
private static final char ETAGE = '!';
private static final char FLUR = '+';
private static final char ZIMMER = '*';


public boolean pruefung() {
   ersteStelleAusrufezeichen = eingabe.indexOf(ETAGE);
   ersteStellePlus = eingabe.indexOf(FLUR);
   ersteStelleSternchen = eingabe.indexOf(ZIMMER);

   letzteStelleAusrufezeichen = eingabe.lastIndexOf(ETAGE);
   letzteStellePlus = eingabe.lastIndexOf(FLUR);
   letzteStelleSternchen = eingabe.lastIndexOf(ZIMMER);

   //Teilstrings auslesen
   ausrufezeichen = eingabe.substring(2, (letzteStelleAusrufezeichen + 1));
   plus = eingabe.substring(letzteStelleAusrufezeichen +2,  letzteStellePlus +1);
   sternchen = eingabe.substring(letzteStellePlus +2,  letzteStelleSternchen +1);

   //Gültigkeit von # testen
   if (eingabe.charAt(0) != BEGINN) {
     return false;
   }

   //Gültigkeit des ersten _ testen
   if (eingabe.charAt(1) != TRENNER) {
     return false;
   }

   //Gültigkeit des zweiten _ testen
   if (eingabe.charAt(letzteStelleAusrufezeichen + 1) != TRENNER) {
     return false; 
   }

   //Gültigkeit des dritten _ testen
   if (eingabe.charAt(letzteStellePlus + 1) != TRENNER) {
     return false; 
   }

   //Gültigkeit von ! testen
   if (ausrufezeichen.length() < 5) {
     //Überprüfen, ob alle chars '!' sind, Wenn nicht false ausgeben
     for (int i=0; i < ausrufezeichen.length(); i++) {
       if (ausrufezeichen.charAt(i) != ETAGE) {
         return false;
       }
     }
   } else {
     return false;
   }

   //Gültigkeit von + testen  
   if (plus.length() < 4) {
     for (int j=0; j < plus.length(); j++) {
       if (plus.charAt(j) != FLUR) {
         return false;
       }
     }
   } else {
     return false;
   }

   //Gültigkeit von * testen  
   if (sternchen.length() < 9) {
     for (int w=0; w < sternchen.length(); w++) {
       if (sternchen.charAt(w) != ZIMMER) {
         return false;
       }
     }
   } else {
     return false;
   } 
  
   return true;
}
 

Blender3D

Top Contributor
Hallo,

wir lernen gerade Java in der Schule und beschäftigen uns gerade mit der Stringverarbeitung.

Wir sollen einen String in dieser Art analysieren

#_!!!_++_**** // Dieser Code entspricht dem Empfänger: Etage 3, Flur 2, Zimmer 4

# -> Beginn der Nachricht
_ -> trennt die Teilbereiche der Nachricht
! -> Anzahl der Etagen
+ -> Anzahl Flur
* -> Anzahl Zimmer

Die Strings können verschieden sein, es ist auch möglich, dass ein String falsch ist. Aber es dürfen maximal 5mal !, 4mal + und 10mal * vorkommen.
Laut Deiner Spezifikation ist auch das ein gültiger String: #_!!!
3 Etagen < 5
0 Flur < 4
0 Zimmer < 10
 

Ähnliche Java Themen

Neue Themen


Oben