【问题标题】:Picocli: Is it possible to define options with a space in the name?Picocli:是否可以在名称中定义带有空格的选项?
【发布时间】:2020-07-26 21:54:58
【问题描述】:

我用谷歌搜索了一下,还搜索了 StackOverflow,当然还有 Picocli 文档,但没有找到任何解决方案。

我工作的公司在批处理程序中使用特殊格式的命令行参数:

-VAR ARGUMENT1=VALUE -VAR ARGUMENT2=VALUE2 -VAR BOOLEANARG=FALSE

(别问我为什么用这种格式,我已经质疑过了,没有得到正确答案。) 现在我想使用 Picocli 进行命令行解析。但是,我无法让它与我们使用的参数格式一起使用,因为空间使 Picocli 认为这是两个独立的参数,因此它不会将它们识别为我定义的参数。

这显然行不通:

@CommandLine.Option( names = { "-VAR BOOLEANARG" } )
boolean booleanarg = true;

使用 -VAR BOOLEANARG=FALSE 调用程序不会有任何效果。

有没有办法自定义定义那些包含空格的特殊选项名称?或者我该怎么做?我也不允许将多个参数作为参数折叠到一个 -VAR 选项中。

非常感谢您的帮助。 谢谢和最好的问候, 罗莎

【问题讨论】:

  • 是的,这可以通过将-VAR 选项定义为Map (picocli.info/#_maps) 来实现。
  • 我在下面提供了更详细的答案。我希望它符合你的要求。享受picocli! :-)

标签: java command-line-arguments picocli


【解决方案1】:

解决方案 1:地图选项

最简单的解决方案是将-VAR 设为Map option。这可能看起来像这样:

@Command(separator = " ")
class Simple implements Runnable {

    enum MyOption {ARGUMENT1, OTHERARG, BOOLEANARG}

    @Option(names = "-VAR",
            description = "Variable options. Valid keys: ${COMPLETION-CANDIDATES}.")
    Map<MyOption, String> options;

    @Override
    public void run() {
        // business logic here
    }

    public static void main(String[] args) {
        new CommandLine(new Simple()).execute(args);
    }
}

此示例的使用帮助如下所示:

Usage: <main class> [-VAR <MyOption=String>]...
      -VAR <MyOption=String>
         Variable options. Valid keys: ARGUMENT1, OTHERARG, BOOLEANARG.

请注意,使用此解决方案,所有值都将具有相同的类型(在此示例中为 String),并且您可能需要在应用。

但是,鉴于您帖子中的这句话,这可能是不可接受的:

我也不允许将多个参数作为参数折叠到一个 -VAR 选项中。

解决方案 2:参数组

一种替代方法是使用argument groups:我们可以将ARGUMENT1OTHERARGBOOLEANARG 设置为单独的选项,并将它们放在一个组中,以便它们必须前面有 -VAR 选项。

生成的使用帮助如下所示:

Usage: group-demo [-VAR (ARGUMENT1=<arg1> | OTHERARG=<otherValue> |
                  BOOLEANARG=<bool>)]... [-hV]
      -VAR                   Option prefix. Must be followed by one of
                               ARGUMENT1, OTHERARG or BOOLEANARG
      ARGUMENT1=<arg1>       An arg. Must be preceded by -VAR.
      OTHERARG=<otherValue>  Another arg. Must be preceded by -VAR.
      BOOLEANARG=<bool>      A boolean arg. Must be preceded by -VAR.
  -h, --help                 Show this help message and exit.
  -V, --version              Print version information and exit.

实现可能如下所示:

@Command(name = "group-demo", mixinStandardHelpOptions = true,
        sortOptions = false)
class UsingGroups implements Runnable {

    static class MyGroup {
        @Option(names = "-VAR", required = true,
          description = "Option prefix. Must be followed by one of ARGUMENT1, OTHERARG or BOOLEANARG")
        boolean ignored;

        static class InnerGroup {
            @Option(names = "ARGUMENT1", description = "An arg. Must be preceded by -VAR.")
            String arg1;

            @Option(names = "OTHERARG", description = "Another arg. Must be preceded by -VAR.")
            String otherValue;

            @Option(names = "BOOLEANARG", arity = "1",
              description = "A boolean arg. Must be preceded by -VAR.")
            Boolean bool;
        }

        // exclusive: only one of these options can follow a -VAR option
        // multiplicity=1: InnerGroup must occur once
        @ArgGroup(multiplicity = "1", exclusive = true)
        InnerGroup inner;
    }


    // non-exclusive means co-occurring, so if -VAR is specified,
    // then it must be followed by one of the InnerGroup options
    @ArgGroup(multiplicity = "0..*", exclusive = false)
    List<MyGroup> groupOccurrences;

    @Override
    public void run() {
        // business logic here

        System.out.printf("You specified %d -VAR options.%n", groupOccurrences.size());
        for (MyGroup group : groupOccurrences) {
            System.out.printf("ARGUMENT1=%s, ARGUMENT2=%s, BOOLEANARG=%s%n",
                    group.inner.arg1, group.inner.arg2, group.inner.arg3);
        }
    }

    public static void main(String[] args) {
        new CommandLine(new UsingGroups()).execute(args);
    }
}

然后,使用java UsingGroups -VAR ARGUMENT1=abc -VAR BOOLEANARG=true 调用会得到:

You specified 2 -VAR options.
ARGUMENT1=abc, OTHERARG=null, BOOLEANARG=null
ARGUMENT1=null, OTHERARG=null, BOOLEANARG=true

使用这种方法,每次最终用户指定-VAR 时,您都会得到一个MyGroup 对象。这个MyGroup 对象有一个InnerGroup,它有很多字段,除了一个之外都是null。只有用户指定的字段不是null。这是这种方法的缺点:在应用程序中,您需要检查所有字段以找到用户指定的非null 字段。好处是通过为@Option-annotated 字段选择正确的类型,值将自动转换为目标类型。

【讨论】:

  • @rosa 这个答案对你有用吗?如果您有更多问题,请告诉我。否则,你能接受这个答案吗?
  • 嗨雷姆科!抱歉回复晚了。这两天我超级忙。非常感谢您的回复!如果对我有用,我会试试这个,然后接受你的回答。
  • 您好 Rosa,感谢您回来。明白了。不用担心!如果有任何不清楚的地方,请随时提出问题。享受picocli! :-)
  • 嗨 Remko,感谢您为我指明地图和群组的方向!我已经玩了一段时间并尝试了两者。我有一些问题。使用 Maps 选项时,我是否必须实现自定义类型转换器,因为参数可以有不同的类型?字符串、布尔值、日期等。然后在自定义转换器中分配适当的类型?但是我会重新发明轮子——有更好的方法吗?对于 Group 选项:我如何确定哪个参数在列表中的哪个位置?我想我必须花更多的时间来进一步探索这一点。
  • 使用地图转换器,所有值最终都为String,应用程序需要转换为所需的类型。这是简单性的缺点。使用 Group 方法,每次最终用户指定 -VAR 时,您都会获得一个 MyGroup 对象。这个MyGroup 对象有一个InnerGroup,它有很多字段,除了一个之外的所有字段都是null。只有用户指定的字段不是null。因此,在应用程序中,您需要检查所有字段以找到用户指定的非null
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2017-02-13
  • 1970-01-01
  • 2010-10-01
  • 2011-07-10
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多