我正在用Java将特定标志解析到我的CLI中。该标志是一个“流”标志,用--stN=
表示,其中N
代表一个从1到10000的数字。
=
之后的参数用逗号分隔,并表示不同的内容-通常是有关如何在程序中运行第N
次的特定命令。
这些命令本身可以具有0..N个参数。
即
--st1=command1,arg1,arg2,command2,arg2,3,command3,command4,5
它们可以是字符串,数字等的组合。
这是我建议的解决方案:
首先,我添加了一个名为StreamOption
的接口来保存已解析的数据:
public interface StreamOption {
}
接下来,我创建了一个StreamOptionParser
来处理流的一部分:
public interface StreamOptionParser<T extends StreamOption> {
StreamReturn parse(List<String> stream, int id) throws ParameterException;
}
在实现中,我将流(作为列表,用逗号分隔)。
例如
public class CommandOneParser implements StreamOptionParser<CommandOneOption> {
StreamReturn parse(List<String> stream, int id) throws ParameterException{
//loop through the list, if terms are found, parse to a StreamObject
//if not, pass to the return list of strings..
}
}
结果类型StreamReturn
是一个简单的POJO,它允许返回已解析的StreamOption
以及需要传递给下一个解析器的所有剩余项。我还需要返回其余的术语,以检查所有输入是否有效,并且没有剩余。
//bit of lombok
@Getter
@Setter
@AllArgsConstructor
public class StreamReturn<T extends StreamOption> {
private List<String> remainingOptions;
private Optional<List<T>> options = Optional.empty();
}
它必须保留List
,因为可以在同一流中指定多个命令。--stN=command1,2,3,command1,4,5,...
这是一个好方法吗?还是有一个更好的解决方案,减少了锅炉的麻烦?这有潜在的问题吗?我认为它保持了可扩展性,并且随着程序的增长,以后我可以轻松添加新的Options
和Parsers
。
我似乎找不到开箱即用的此类解析库/模式,有没有我可能想念的东西?我将JCommander用于简单的标志,但这对于jcommander来说似乎太复杂了。
预先感谢, 山姆
答案 0 :(得分:0)
因此, 的答案是通过分割字符串将其视为常规的CLI参数。然后,我利用JCommander进行所有耗时的工作,将正确的命令推入正确的转换器。
command1,2,3,command2,3,string1,command3
进入
command1
,
2,3
,
command2
,
3,string1
,
command3
有了这个,我利用JCommander批注将正确的args传递给正确的命令。
CommandOneValues{
int myValue1;
int myValue2;
}
和选项:
@Getter
public class CommandOneOptions {
@Parameter(names = {"command1"},
converter = CommandOneConverter.class
)
CommandOneValues values;
}
具有一个简单的转换器:
class CommandOneConverter implements IStringConverter<CommandOneValues>{
public CommandOneValues convert(String value){
//conversion...
}
}
希望这对以后的人有帮助!
答案 1 :(得分:0)
其他工具可能具有一些功能,这些功能除了可以提供自定义类型转换器之外,还可以为其他解决方案提供思路。 例如,picocli具有一些可能有趣的复杂选项机制:
引用的选项
假设您对选项的定义如下:
@Option(names = "--st", split = ",")
List<String> parts;
默认情况下,picocli的split
函数在引号内出现时会忽略split
regex,因此您可以使用引号对参数进行分组。用户输入示例:
--st1="command1,arg1,arg2","command2,arg2,3","command3","command4,5"
Picocli将这些值分成以下几个部分:
"command1,arg1,arg2"
"command2,arg2,3"
"command3"
"command4,5"
以上是拆分的默认行为,不需要自定义转换器或任何其他自定义代码。
参数组
Picocli 4.0将支持重复的参数组(仍处于beta中),这可能是对问题进行建模的另一种方式。 如果应用程序的概要看起来像这样,对最终用户不好吗?
myapp (--cmd=<commandName> [<commandArg>...])...
也就是说,--cmd
选项与零个或多个位置参数一起成为参数组,并且可以为该参数组指定一次或多次。
最终用户将能够输入如下值:
myapp --cmd=command1 arg1 arg2 --cmd=command2 arg2 3 --cmd=command3 --cmd=command4 5
完成此操作的代码如下:
@Command(name = "myapp", mixinStandardHelpOptions = true)
class MyApp implements Callable<Integer> {
static class CommandDefinition {
@Option(names = "--cmd", required = true) String commandName;
@Parameters(index = "0..*") List<String> commandArgs;
}
@ArgGroup(exclusive = false, multiplicity = "1..*")
List<CommandDefinition> commands = new ArrayList<>();
public Integer call() throws Exception {
// your business logic here
return 0;
}
public static void main(String... args) {
int exitCode = new CommandLine(new MyApp()).execute(args);
System.exit(exitCode);
}
}