Простое перечисление для Java-автомата

Я пытаюсь реализовать этот пример автомата: http://www.javacodegeeks.com/2012/03/automaton-implementation-in-java.html.

Однако при запуске программы продолжает отображаться ошибка:

Exception in thread "main" java.lang.StringIndexOutOfBoundsException: 
           String index out of range: 3
at java.lang.String.charAt(String.java:686)
at mealy.Input.read(Input.java:7)
at mealy.States$4.next(Input.java:46)
at mealy.Test.main(Test.java:9)

Я попытался изменить строки, ответственные за ошибку, но ничего не изменилось. Может ли кто-нибудь взглянуть на эту программу и помочь мне найти решение?

У меня есть следующий .java:

State.java:

interface State {
    public State next(Input in);
}

Примечание: мне пришлось изменить исходный "public Stat next()" на "public State next(Input in);"

Input.java:

class Input {
    private String input;
    private int current;
    public Input(String input) {this.input = input;}
    char read() { return input.charAt(current++); }
}

enum States implements State {
    Init {
        @Override
        public State next(Input word) {
            switch(word.read()) {
                case 'a': return A;
                default: return Fail;
            }
        }
    },
    A {
        @Override
        public State next(Input word) {
            switch(word.read()) {
                case 'a': return A;
                case 'b': return B;
                case 'c': return C;
                case 'd': return null;
                default: return Fail;
            }
        }
    },
    B {
        @Override
        public State next(Input word) {
            switch(word.read()) {
                case 'b': return B;
                case 'c': return C;
                case 'd': return null;
                default: return Fail;
            }
        }
    },
    C {
        @Override
        public State next(Input word) {
            switch(word.read()) {
                case 'c': return C;
                case 'd': return null;
                default: return Fail;
            }
        }
    },
    Fail {
        @Override
        public State next(Input word) {
               return Fail;
        }
    };

    public abstract State next(Input word);
}

Test.java:

public class Test {
    public static void main(String args[]){
        State s;
        Input in = new Input("abc");

        for(s = States.Init; s != null || s != States.Fail; s = s.next(in)) {}
        if(s == States.Init) {System.out.println("Valid!");}
        else {System.out.println("Failed");}
    }
}

person Fabrice Sopoglian    schedule 04.11.2013    source источник


Ответы (3)


Похоже, в классе Input есть ошибка. Когда вы пытаетесь прочитать символ после последнего, он выдает исключение, которое вы не обрабатываете в main. Я бы изменил Input так, чтобы он возвращал токен, который вы можете обрабатывать в своей конечной машине.

Кстати, я предлагаю вам взглянуть на это для контекста. http://vanillajava.blogspot.co.uk/2011/06/java-secret-using-enum-as-state-machine.html

Я предполагаю, что Аттила хотел предоставить простой рабочий пример. Я посмотрю, сможет ли он исправить свой код.

person Peter Lawrey    schedule 04.11.2013

вам нужно изменить read() method, как показано ниже

char read() { 
    if(current>=input.length())      // this if condition should be checked
          return 'z';                // you need to change your character according to your need
    return input.charAt(current++); 
}
person Prabhakaran Ramaswamy    schedule 04.11.2013
comment
ммм... вы бы изменили логику, чтобы она бесконечно возвращала char 'z' для всех переполнений? вы уверены, что это будет лучший способ? - person eis; 04.11.2013
comment
@eis, я согласен, что OP вернет его неиспользованный символ из оператора switch. - person Prabhakaran Ramaswamy; 04.11.2013
comment
Спасибо за ваши ответы, но на самом деле ваше решение ByteCode, похоже, только переносит проблему в другую точку. Я провел свой день, пытаясь найти способ контролировать чтение тока, я просто смог разорвать цикл на Test.java, как только было достигнуто состояние C. Это не позволяет методу read() продолжать чтение слова, но я ищу лучший способ его контролировать. У вас есть идеи? - person Fabrice Sopoglian; 05.11.2013

ошибка именно в этой строке

char read() { return input.charAt(current++); }

Вы не проверяете длину строки input (которую я считаю плохим именем внутри класса Input), и после трехкратного вызова read() вы пытаетесь получить доступ к 4-й букве трехбуквенной строки, которая затем выдает исключение, которое вы видите.

Обновлять:

Обращаясь к вашему комментарию, я бы предложил изменить возвращаемое значение read() на новый интерфейс ReadResult:

public interface ReadResult {
    boolean isOkay();
    char getReadCharacter();  
}

с двумя реализациями. один для положительных результатов...

public class ReadOkay implements ReadResult{
    private char readCharacter;

    public ReadOkay(char readCharacter) {
        this.readCharacter = readCharacter;
    }

    @Override
    public boolean isOkay() {
        return true;
    }

    @Override
    public char getReadCharacter() {
        return readCharacter;
    }
}

и один для отрицательных результатов

public class ReadFailed implements ReadResult {

    @Override
    public boolean isOkay() {
        return false;
    }

    @Override
    public char getReadCharacter() {
        throw new IllegalStateException("Read failed! no character data there to return!");
    }
}

Имея это, вы можете изменить read(), чтобы он вернулся, а затем новый интерфейс.

public ReadResult read() {
        if (input != null && current >= 0 && current < input.length()) {
            return new ReadOkay(input.charAt(current++));
        } else {
            return new ReadFailed();
        }
    }

и обновите свои состояния соответственно.

заменять:

switch(word.read()) {

с:

ReadResult result = word.read();
if (!result.isOkay()) {
    return Fail;
}
switch (result.getReadCharacter()) {
person Marco Forberg    schedule 04.11.2013
comment
Спасибо, вы правы. Но поскольку я не могу добавить какое-либо условие для текущего размера, я не могу решить эту проблему. У вас есть идея? - person Fabrice Sopoglian; 05.11.2013
comment
Марко Форберг, большое спасибо за ваш ответ. Я не смог проверить это до сих пор, поэтому я отвечаю так поздно. В очередной раз благодарим за помощь ! - person Fabrice Sopoglian; 18.11.2013