以相同方式解析文件和命令行选项

时间:2019-04-15 19:01:00

标签: java

我在Java中编写了一个脚本(不确定是否是写术语)。 用户可以通过两种方式指定环境变量:命令行或在文件中。 命令行如下所示(用~~~分隔)

ENV1=1~~~ENV2=String2

文件如下:

setenv ENV1 1
setenv ENV2 String2

我编写了一个函数,该函数返回env的集合(因此输出为:{ENV2=String2, ENV1=1})。 它看起来如下:

public Map<String, String> getEnvs() {
    final String envArg = getOption(cmdNames.ENV); // returns the path or the command-line options
    if (null != envArg && !"".equals(envArg) && envArg.contains("=")) {
        final String varArray[] = envArg.split("~~~"); // split by a special string
        final Map<String, String> new_vars = new HashMap<String, String>();
        for (final String var : varArray) {
            final String varName = var.split("=")[0];
            String varValue = var.split("=")[1];
            if (!varValue.contains("\"") && varValue.contains(" ")) {
                varValue = "\"" + varValue + "\"";
            }
            new_vars.put(varName, varValue);
        }
        return new_vars;
    }
    return null;
}

现在,我为命令行选项编写了一个函数。我想添加对文件选项的支持。问题在于这些选项的外观不同-我需要用~~~分割其中一个,而用setenv分割另一个。 我很高兴听到关于如何在同一getEnvs函数中添加对文件选项的支持的建议。 我脑子里已经有了一些实现,但是它变得一团糟,我正在寻找最干净的方法。 (据我了解,我们需要将文件中的数据插入到数组中并用setenv进行拆分,但是我们还需要在namevalue之间进行拆分-感觉代码可以使用了两次,但我不确定哪个部分可以解决问题。

1 个答案:

答案 0 :(得分:0)

您似乎试图解决的问题似乎可以通过策略模式来最好地解决。

文件的内容和命令行都可以用字符串表示。这些字符串可以由某种类型的解析器处理,这些解析器可以根据您的意愿使用不同的策略。

看起来像这样

public static void main(String... args) throws IOException{
    boolean parseFromFile = true; //whatever criteria you want to use
    String content;
    Parser p;
    String fileName = "yikes";
    if(parseFromFile){
        p = new Parser(new FileParseStrategy());
        //we need to read contents of file prior to parsing
        content = Files.readAllLines(Paths.get(fileName)).stream()
                .collect(Collectors.joining(System.lineSeparator()));
    }
    else {
        p = new Parser(new CmdLineParseStrategy());
        content = getContent(cmdNames.ENV); //just coping what you used.
    }
    Map<String, String> vars = p.run(content);
}

public class Parser{
    final ParseStrategy parseStrategy;

    public Parser(ParseStrategy ps) {
        this.parseStrategy = ps;
    }

    public Map<String, String> run(String input){
        return parseStrategy.parse(input);
    }
}

public interface ParseStrategy {
    Map<String, String> parse(String input);
}

public class FileParseStrategy implements ParseStrategy{

    @Override
    public Map<String, String> parse(String input) {
        Map<String, String>  result = new HashMap<>();
        for(String line : input.split("\r?\n|\r")) {
            String[] parts = validate(line.split(" "));
            result.put(parts[1], parts[2]);
        }
        return result;
    }

    private String[] validate(String[] parts) {
        if(parts.length != 3) {
            throw new IllegalArgumentException("3 parts needed");
        }
        if(!parts[0].equalsIgnoreCase("setenv")){
            throw new IllegalArgumentException("unrecognized cmd");
        }
        return parts;
    }
}
//given implementation of parsing from command line.
public class CmdLineParseStrategy implements ParseStrategy {

    @Override
    public Map<String, String> parse(String envArg) {
        if (null != envArg && !"".equals(envArg) && envArg.contains("=")) {
            final String varArray[] = envArg.split("~~~"); // split by a special string
            final Map<String, String> new_vars = new HashMap<String, String>();
            for (final String var : varArray) {
                final String varName = var.split("=")[0];
                String varValue = var.split("=")[1];
                if (!varValue.contains("\"") && varValue.contains(" ")) {
                    varValue = "\"" + varValue + "\"";
                }
                new_vars.put(varName, varValue);
            }
            return new_vars;
        }
        return null;
    }
}