gpt4 book ai didi

java - Commons CLI 中的 DefaultParser 的行为与已弃用的解析器不同

转载 作者:行者123 更新时间:2023-11-30 02:50:08 31 4
gpt4 key购买 nike

问题

我正在尝试以任何顺序解析一些命令行参数。其中两个是单值且强制的,另一个是可选的逗号分隔列表:

usage:
-mo <value1,value2,...,valueN>
-sm1 <value>
-sm2 <value>

使用任何旧的解析器(BasicParserPosixParserGnuParser),代码都可以正常工作,但如果我使用 DefaultParser 相反,会抛出 MissingOptionException

代码

import java.util.Arrays;

import org.apache.commons.cli.CommandLine;
import org.apache.commons.cli.CommandLineParser;
import org.apache.commons.cli.DefaultParser;
import org.apache.commons.cli.Option;
import org.apache.commons.cli.Options;

public class Foo {

public static void main(String[] args) throws Exception {

Option singleMandatory1 = Option.builder("sm1")
.argName("value")
.hasArg()
.required()
.build();
Option singleMandatory2 = Option.builder("sm2")
.argName("value")
.hasArg()
.required()
.build();
Option multipleOptional = Option.builder("mo")
.argName("value1,value2,...,valueN")
.hasArgs()
.valueSeparator(',')
.build();

Options options = new Options();
options.addOption(singleMandatory1);
options.addOption(singleMandatory2);
options.addOption(multipleOptional);

CommandLineParser parser = new DefaultParser();
CommandLine line = parser.parse(options, args);

for (Option o : line.getOptions()) {
System.out.println(o.getOpt() + '\t'
+ Arrays.toString(o.getValues()));
}
}
}

命令行参数

-sm1 Alice -sm2 Bob -mo Charles,David 有效

-sm1 Alice -mo Charles,David -sm2 Bob 仅使用旧的(现已弃用)解析器工作

我错过了什么吗?我正在使用 commons-cli-1.4-SNAPSHOT

感谢您的帮助。

最佳答案

我认为这是 DefaultParser 中的一个错误。最终归结为这个方法:

/**
* Tells if the token looks like a short option.
*
* @param token
*/
private boolean isShortOption(String token)
{
// short options (-S, -SV, -S=V, -SV1=V2, -S1S2)
return token.startsWith("-") && token.length() >= 2 &&
options.hasShortOption(token.substring(1, 2));
}

(断行以便更容易阅读)。

不幸的是,由于最后一个子句 options.hasShortOption(token.substring(1, 2)),对于超过一个字符的“短选项”,这将始终返回 false 它肯定会在 return 语句之前的注释中的第 2、3 和 4 项上失败,这让我相信这是一个错误 。我可能误解了评论背后的意图,所以请忽略之前的声明。

修复可能如下所示:

/**
* Tells if the token looks like a short option.
*
* @param token
*/
private boolean isShortOption(String token)
{
// short options (-S, -SV, -S=V, -SV1=V2, -S1S2)
// extended to handle short options of more than one character
if (token.startsWith("-") && token.length() >= 2)
{
return options.hasShortOption(token.substring(1, 2)) ||
options.hasShortOption(extractShortOption(token));
}
return false;
}

/**
* Extract option from token. Assume the token starts with '-'.
*/
private String extractShortOption(String token)
{
int index = token.indexOf('=');
return (index == -1) ? token.substring(1) : token.substring(1, index);
}

不幸的是,没有很好的方法将其放入 DefaultParser 中,因为方法是私有(private)的,调用方法是私有(private)的(isOptionisArgumenthandleToken)和 DefaultParser 依赖于 Options 中的包本地方法。

我测试修复的方法是将 DefaultParser 复制/粘贴到我的本地项目中,移至 org.apache.commons.cli 包并进行上述更改。

<小时/>

作为解决问题中特定情况的狡猾方法,您可以添加一个虚拟短选项“s”,这会欺骗isShortOption(...)sm1 和/或 sm2 选项返回 true。像这样的事情:

    Option singleMandatory1 = Option.builder("sm1")
.argName("value")
.hasArg()
.required()
.build();
Option singleMandatory2 = Option.builder("sm2")
.argName("value")
.hasArg()
.required()
.build();
Option multipleOptional = Option.builder("mo")
.argName("value1,value2,...,valueN")
.hasArgs()
.valueSeparator(',')
.build();
Option dummyOptional = Option.builder("s")
.build();

Options options = new Options();
options.addOption(singleMandatory1);
options.addOption(singleMandatory2);
options.addOption(multipleOptional);
options.addOption(dummyOptional);

CommandLineParser parser = new DefaultParser();
CommandLine line = parser.parse(options, args);
<小时/>

ASF JIRA 上的此问题似乎捕获了该问题,尽管触发情况略有不同:https://issues.apache.org/jira/browse/CLI-265

关于java - Commons CLI 中的 DefaultParser 的行为与已弃用的解析器不同,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/38964866/

31 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com