用于创建控制台命令的Java库

时间:2011-06-07 08:51:17

标签: java console-application

是否有一个公共库可以帮助实现在Java控制台程序中输入的命令?我不是指用于解析诸如Commons CLI之类的Java命令行选项的库。我在谈论创建在进入控制台的正在运行的Java程序中使用的命令:

  

>连接127.0.01

     

连接!

     

>加载poem.txt 23

     

...装载

这样的东西 - 我可以自己写,但问题是,是否已有图书馆。


我最终使用了一个抽象类Command的继承。它有execute()和Java反射我解析输入并从它的第一个输入参数接收命令类:

connect ... - > ConnectCommand

4 个答案:

答案 0 :(得分:2)

您可以使用parser执行此操作。您希望获取一些自由格式文本并将其转换为表示用户键入的表达式的相应Java对象。

有很多库可供重量级(例如AntLR)更简单(例如JParsec)。您也可以选择使用正则表达式手动执行此操作。

答案 1 :(得分:2)

您可能需要查看JLine。它类似于BSD editline和GNU readline。

答案 2 :(得分:1)

当我需要这样的东西但我没有真正完成时,我曾经开始过类似的项目。

虽然有naturalcli。也许这适合你。

答案 3 :(得分:0)

我有一个很好的设计模式来做这样的事情,它不涉及任何库,并且很容易实现。

步骤:
1.使用正则表达式解析命令,创建如下所示的枚举类 2.创建一个主循环,它从控制台读取,从1遍及以上解析命令到该枚举。
3.使用开关箱将命令分配给正确的方法。

ad 1.)包含所有命令的枚举类。如果需要,您还可以外部化这些字符串。 对于rawCommand,它应该是不可变的。更好的是,创建一个包含rawCommand和enum作为字段的类。

package issue.system.core;

import java.util.Optional;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import issue.system.model.IssueState;

/**
 * Command enumeration containing plenty of useful methods to parse commands
 * @author Alessandro Giusa
 * @version 1.0
 *
 */
public enum Command {

    INIT("^init$"),
    ISSUE("^issue #([A-Za-z0-9_])+$"),
    OPEN("^open #([A-Za-z0-9_])+$"),
    SHOW("^show(( #([A-Za-z0-9_])+( ([0-9])+)?)|( #([A-Za-z0-9_])+ tags)|( t([A-Za-z0-9_])+)(,t([A-Za-z0-9_])+)*)?( -s[0-9](-[0-9]+)?)?( -f (and|or))?$"),
    REMOVE("^remove(( #([A-Za-z0-9_])+( t([A-Za-z0-9_])+)?)|(( t([A-Za-z0-9_])+)(,t([A-Za-z0-9_])+)* (-f (and|or)))|( released))$"),
    RENAME("^rename( #([A-Za-z0-9_])+ #([A-Za-z0-9_])+)|(( t([A-Za-z0-9_])+ t([A-Za-z0-9_])+))$"),
    STATE("^state #([A-Za-z0-9_])+ (" + IssueState.getRegexForCommand() + "$"),
    HELP("^help$"),
    QUIT("(^quit)|(^q)$"),
    QUIT_AND_COMMIT("(^qc)$"),
    TAG("^tag(( #([A-Za-z0-9_])+( t([A-Za-z0-9_])+)(,t([A-Za-z0-9_])+)*)|(( t([A-Za-z0-9_])+)(,t([A-Za-z0-9_])+)*)|( -r( t([A-Za-z0-9_])+)(,t([A-Za-z0-9_])+)*))?$"),
    CLEAR("^clear$"),
    GIT("^git( commit)?$"),
    PATCH_NOTES("^patchnotes$")
    ;

    public static final String DELIMITER_COMMAND_TOKEN_COMMAND_TEXT = " ";
    private final String regex;
    private String rawCommand;

    private Command(final String regex) {
        this.regex = regex;
    }

    public String getRegex() {
        return this.regex;
    }

    public String getRawCommand() {
        return this.rawCommand;
    }

    public void setRawCommand(final String rawCommand) {
        this.rawCommand = rawCommand;
    }

    /**
     * Parse the given raw string into a command if there is one corresponding to
     * @param rawString
     * @return option to command
     */
    public static Optional<Command> parseCommand(final String rawString) {
        Matcher matcher;
        for (final Command nextCommand : values()) {
            matcher = Pattern.compile(nextCommand.getRegex()).matcher(rawString);
            if (matcher.find()) {
                final String rawCommand = rawString.substring(
                        rawString.indexOf(DELIMITER_COMMAND_TOKEN_COMMAND_TEXT, 0) 
                        + 1, rawString.length());
                nextCommand.setRawCommand(rawCommand);
                return Optional.of(nextCommand);
            }
        }
        return Optional.empty();
    }
}

这是我在命令行问题系统中使用的类。

ad 2.) 从命令行一遍又一遍地读取的主循环。 Terminal类只是sys-out东西的一个方便的类。

@Override
public void run() {
    this.running = true;
    while (this.running) {
        final String line = Terminal.readLine(CURSOR);
        if(line == null) {
            Terminal.println("cmd line was empty");
            continue;
        }
        final Optional<Command> optCommand = Command.parseCommand(line);
        if (optCommand.isPresent()) {
            if (optCommand.get() == Command.INIT || this.loadIssueMetadata(optCommand.get())) {
                this.processCommand(optCommand.get());
            }
        } else {
            Terminal.printf("the given command %s is not a vaild. Use <help> to see all commands.", line);
        }
    }
    System.exit(0);
}

ad 3.)以及将命令分派给正确方法进行处理的switch-case部分。

void processCommand(final Command command) {
    switch (command) {
    case INIT:
        this.init();
        break;
    case ISSUE:
        this.issue(command.getRawCommand());
        break;
    case SHOW:
        this.show(command.getRawCommand());
        break;
    case QUIT:
        this.quit();
        break;
    case STATE:
        this.state(command.getRawCommand());
        break;
    case REMOVE:
        this.remove(command.getRawCommand());
       break;
    case RENAME:
        this.rename(command.getRawCommand());
        break;
    case HELP:
        usage();
        break;
    case TAG:
        this.tag(command.getRawCommand());
        break;
    case OPEN:
        this.open(command.getRawCommand());
        break;
    case CLEAR:
        this.cls();
        break;
    case GIT:
        this.git(command.getRawCommand());
        break;
    case QUIT_AND_COMMIT:
        this.quitAndCommit();
        break;
    case PATCH_NOTES:
        this.patchNotes();
        break;
    default:
        break;
    }
}

我希望你明白了。如果您有兴趣,请告诉我!

良好的编程!