Java控制台输入处理

Java控制台输入处理,java,validation,input,console,Java,Validation,Input,Console,这是我在这里的第一个问题,我希望它不是基于太多的意见。我在互联网上搜索了很长一段时间,但没有找到类似的问题。 我需要编写一个Java程序,从控制台读取命令,验证输入,获取参数并将其传递到另一个类。 我可以做什么和使用什么(大学)有一些限制。 只允许包java.util、java.lang和java.io 每种方法只能有80行 每行只能有120个字符长 我不允许使用System.exit/Runtime.exit 终端类用于处理用户输入Terminal.readLine()将从控制台读取一行,如

这是我在这里的第一个问题,我希望它不是基于太多的意见。我在互联网上搜索了很长一段时间,但没有找到类似的问题。
我需要编写一个Java程序,从控制台读取命令,验证输入,获取参数并将其传递到另一个类。
我可以做什么和使用什么(大学)有一些限制。

  • 只允许包java.util、java.lang和java.io
  • 每种方法只能有80行
  • 每行只能有120个字符长
  • 我不允许使用System.exit/Runtime.exit
  • 终端类用于处理用户输入
    Terminal.readLine()
    将从控制台读取一行,如
    Scanner.nextLine()
我有一个完全可以工作的程序-但是我的解决方案不会被接受,因为我处理控制台输入的方式(
runInteractionLoop()
method太长)。我是这样做的:

  • main类有main方法和一个“交互循环”,在这里处理控制台输入。main方法在while循环中调用交互循环,以布尔值“quit”作为监护人

    private static boolean quit = false;
    ...
    public static void main(String[] args) {
        ...
        while (quit == false) {
            runInteractionLoop();
        }
    }
    
  • 交互循环处理控制台输入。我需要检查16个不同的命令-每个命令都有自己的参数类型。我选择使用模式和匹配器,因为我可以方便地使用这些组。现在问题开始了——我从未学会如何正确处理用户输入。我在这里所做的是,对于每个可能的命令,创建一个新的匹配器,查看输入是否匹配,如果匹配,则为该输入执行任何需要执行的操作

    private static runInteractionLoop() {
        Matcher m;
        String query = Terminal.readLine;
        m = Pattern.compile("sliding-window (\\d+) (-?\\d+(?:\\.\\d+)?;)*(-?\\d+(?:\\.\\d+)?)").matcher(query);
        if (m.matches()) {
            xyz.doSth(Integer.parseInt(m.group(1)), ......);
            ...
            return;
        }
        m = Pattern.compile("record ([a-z]+) (-?\\d+(?:\\.\\d+)?)").matcher(query);
        if (m.matches()) {
            xyz.doSthElse(m.group(1), Double.parseDouble(m.group(2)));
            return;
        }
        ...
        if (query.equals("quit")) {
            quit = true;
            return;
        }
        Terminal.printError("invalid input");
    }
    
  • 如您所见,执行此操作16次可将方法扩展到80多行(每个输入最多5行)。这显然也是非常低效的,老实说,我很惭愧在这里发布这个(垃圾代码)。我只是不知道如何正确地做到这一点,只使用java.util,并且有一些方法可以快速获取参数(例如,这里的匹配器组)。

    有什么想法吗?我将非常感谢您的建议。谢谢

    编辑/更新:

    我决定将验证分为两种方法——每一半命令一种。看起来很难看,但通过了Uni的checkstyle要求然而,如果有人能为我的问题提供更好的解决方案,我还是会非常高兴的——为了将来(因为我显然不知道如何使这个问题变得更漂亮、更短和/或更高效)。

    我想你可以尝试类似这样痛苦的方法,将所有内容都分成一系列方法调用:

    private static runInteractionLoop() {
        Matcher m;
        String query = Terminal.readLine;
        m = Pattern.compile("sliding-window (\\d+) (-?\\d+(?:\\.\\d+)?;)*(-?\\d+(?:\\.\\d+)?)").matcher(query);
        if (m.matches()) {
            xyz.doSth(Integer.parseInt(m.group(1)), ......);
            ...
            return;
        } else {
            tryDouble(query, m);
        }
    }
    
    Private  static tryDouble(String query, Matcher m) {
        m = Pattern.compile("record ([a-z]+) (-?\\d+(?:\\.\\d+)?)").matcher(query);
        if (m.matches()) {
            xyz.doSthElse(m.group(1), Double.parseDouble(m.group(2)));
            return;
        } else {
            trySomethingElse(query, m);
        }
    }
    
    Private static trySomethingElse(String query, Matcher m) {
        ...
        if (query.equals("quit")) {
            quit = true;
            return;
        }
        Terminal.printError("invalid input");
    }
    

    通过将匹配工作委托给子方法,可以将每种可能性归结为两行(如果分隔行上必须有结束括号,则为三行):

    if ( Matcher m = matches( query, "sliding-window (\\d+) (-?\\d+(?:\\.\\d+)?;)*(-?\\d+(?:\\.\\d+)?)") != null)
        xyz.doSth(Integer.parseInt(m.group(1)), ......);
    else if ( Matcher m = matches( query, "record ([a-z]+) (-?\\d+(?:\\.\\d+)?)") != null)
        xyz.doSthElse(m.group(1), Double.parseDouble(m.group(2)));
    ...
    else
    
    
    private Matcher matches( String input, String regexp)
    {
        Matcher result = Pattern.compile(regexp).matcher(input);
        if ( result.matches() )
            return result;
        else
            return null;
    }
    

    我会用一个抽象类
    CommandValidator
    来解决这个问题:

    public abstract class CommandValidator {
    
        /* getter and setter */
    
        public Matcher resolveMatcher(String query) {
            return Pattern.compile(getCommand()).matcher(query);
        }
    
        public abstract String getCommand();
    
        public abstract void doSth();
    }
    
    将为每个处理程序实现16个不同的CommandValidator,并以不同的方式实现抽象方法:

    public class IntegerCommandValidator extends CommandValidator {
    
        @Override
        public String getCommand() {
            return "sliding-window (\\d+) (-?\\d+(?:\\.\\d+)?;)*(-?\\d+(?:\\.\\d+)?)";
        }
    
        @Override
        public void doSth() {
            /* magic here, parameter input the matcher and xyz, or have it defined as field at the class */
            // xyz.doSth(Integer.parseInt(m.group(1)), ......);
        }
    }
    
    由于在
    CommandValidator
    中需要匹配器,因此可以将其设置为类的字段,或者将其放入
    doSth()
    方法中

    然后,您可以实例化列表中的每个具体验证器,并迭代每个验证器,解析匹配器并查看它是否匹配:

      private static Set<CommandValidator> allConcreteValidators;
      public static void main(String[] args) {
          /* */
          allConcreteValidators.add(new IntegerCommandValidator());
          /* */
          while (quit == false) {
            runInteractionLoop();
          }
      }
    
      private static runInteractionLoop() {
          String query = Terminal.readLine;
          for (CommandValidator validator : allConcreteValidators) {
              if (validator.resolveMatcher(query).matches()) {
                  validator.doSth();
              }
          }
      }
    
    私有静态设置AllConcreteValidator;
    公共静态void main(字符串[]args){
    /* */
    添加(新的IntegerCommandValidator());
    /* */
    while(quit==false){
    runInteractionLoop();
    }
    }
    私有静态runInteractionLoop(){
    字符串查询=Terminal.readLine;
    for(CommandValidator验证程序:allConcreteValidators){
    if(validator.resolveMatcher(query.matches()){
    validator.doSth();
    }
    }
    }
    
    当然,如果有一个验证器适合并处理您没有定义任何验证器的情况,那么您以前可以构建一个查找方法

    对于你的运动来说,可能有点过度设计了。如果具体验证器也共享相同的Doth magic,那么您可以将该命令输入到具体验证器的构造函数中。
    Ofc您应该为这些类找到更好的名称,因为它不仅是一个验证器,而且还有一些不同的功能。

    您的意思是不允许您使用java.util.regex吗?@Heri不,我可以使用java.util、java.io和java.lang包中的所有类,但只能使用这些类。目前的情况是,我可能会创建另一个方法
    runInteractionLoop2()
    ,并将验证的一半转移到该方法上——但这就像#@$一样难看!这不是一个明确的答案。regex是java.util的一个子包。你是否可以使用它?16种不同的可能性到底有什么不同?是的,痛苦是正确的词。。。这是我的最后一个选择,只需为每个查询添加一个方法,该查询需要多个线性行进行验证。这将使我精确到80行。是的,这看起来是一个很好的解决问题的方法。稍后我将尝试此方法,并报告它是否与我的Uni的限制性检查样式一起工作。如果您使用的是java8,您甚至可以使用一个或两个线性程序来解决它,如果您定义了前几个查找表(最小值:命令字符串和相应处理程序之间的映射),嗯。。。你确定这样行吗?由于
    匹配(字符串输入,字符串regexp)
    返回一个
    匹配器
    ,if语句的布尔值是多少?另外,我对Java8解决方案非常感兴趣:)我对查找表的建议将首先涉及对不同命令的深入分析(如何区分它们,以及它们都有哪些共同点,哪些命令需要哪些类型的参数等等)。看起来要做很多工作。这很有趣!!对于这个练习来说,确实有点过度设计了,但是看起来很好,结构也很好。我喜欢这个,谢谢!