【问题标题】:Simple enum for java automatonjava自动机的简单枚举
【发布时间】:2013-11-14 20:32:09
【问题描述】:

我正在尝试实现这个自动机示例: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");}
    }
}

【问题讨论】:

    标签: java enums compiler-errors fsm automaton


    【解决方案1】:

    Input 类中似乎存在错误。当您尝试读取最后一个字符之后的字符时,它会引发您未在 main.xml 中处理的异常。我会更改 Input 以便它返回一个您可以在您的状态机中处理的令牌。

    顺便说一句,我建议你看看这个上下文。 http://vanillajava.blogspot.co.uk/2011/06/java-secret-using-enum-as-state-machine.html

    我认为 Attila 正在寻求提供一个简单、有效的示例。我会看看他是否可以修复他的代码。

    【讨论】:

      【解决方案2】:

      您需要更改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++); 
      }
      

      【讨论】:

      • 嗯......你会改变逻辑,以便它会无限期地返回所有溢出的char'z'?你确定那是最好的方法吗?
      • @eis 我同意你的 OP 会从 switch 语句中返回他未使用的字符。
      • 感谢您的回答,但实际上 ByteCode 您的解决方案似乎只是将问题转移到另一点。我花了一天的时间试图找到一种方法来控制“当前”的读取,一旦达到状态“C”,我就能够打破 Test.java 上的循环。它阻止了 read() 方法在单词的阅读中走得更远,但我正在寻找一种更好的方法来控制它。你有什么想法吗?
      【解决方案3】:

      错误在这一行

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

      您没有检查字符串 input 的长度(我认为这是在类 Input 中的坏名称)并且在调用 read() 三次后,您尝试访问 3 个字母字符串的第 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()) {
      

      【讨论】:

      • 谢谢你,你是对的。但由于我无法在“当前”大小上添加任何条件,因此无法解决此问题。你有什么想法吗?
      • Marco Forberg,非常感谢您的回答。到目前为止我无法对其进行测试,这就是我回答这么晚的原因。再次感谢您的帮助!
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多