将包含命令行参数的字符串拆分为Java中的String

与C#的这个线程类似,我需要将包含命令行参数的字符串拆分到我的程序中,这样我就可以让用户轻松运行多个命令。 例如,我可能有以下字符串:

-p /path -d "here's my description" --verbose other args 

鉴于上述情况,Java通常会将以下内容传递给main:

 Array[0] = -p Array[1] = /path Array[2] = -d Array[3] = here's my description Array[4] = --verbose Array[5] = other Array[6] = args 

我不需要担心任何shell扩展,但它必须足够聪明,以处理单引号和双引号以及字符串中可能存在的任何转义。 有没有人知道在这些条件下shell会解析字符串的方法?

注意 :我不需要进行命令行解析,我已经使用joptsimple来做到这一点。 相反,我想让我的程序易于编写脚本。 例如,我希望用户能够在一个文件中放置一组命令,每个命令在命令行上都是有效的。 例如,他们可能会在文件中键入以下内容:

 --addUser admin --password Admin --roles administrator,editor,reviewer,auditor --addUser editor --password Editor --roles editor --addUser reviewer --password Reviewer --roles reviewer --addUser auditor --password Auditor --roles auditor 

然后用户将运行我的管理工具,如下所示:

 adminTool --script /path/to/above/file 

然后main()将找到--script选项并迭代文件中的不同行,将每行拆分为一个数组,然后我将在joptsimple实例中将其reflection,然后将其传递到我的应用程序驱动程序中。

joptsimple带有一个具有parse方法的Parser,但它只支持一个String数组。 类似地, GetOpt构造函数也需要String[] – 因此需要解析器。

这是将文本行从文件拆分为参数向量的一种非常简单的替代方法,以便您可以将其提供给选项解析器:

这是解决方案:

 public static void main(String[] args) { String myArgs[] = Commandline.translateCommandline("-a hello -b world -c \"Hello world\""); for (String arg:myArgs) System.out.println(arg); } 

魔术类Commandlineant的一部分。 因此,您必须将ant放在类路径上,或者只使用Commandline类,因为使用的方法是静态的。

您应该使用function齐全的现代对象命令行参数解析器我建议我最喜欢的Java Simple Argument Parser 。 以及如何使用JSAP ,这是以Groovy为例,但直接Java也是如此。 还有args4j在某些方面比JSAP更现代,因为它使用注释,远离apache.commons.cli的东西,它是旧的和破坏的,并且在其API中非常过程和非Java等。 但我仍然依赖于JSAP,因为构建自己的自定义参数处理程序非常容易。

URL,数字,InetAddress,颜色,日期,文件,类等都有很多默认的解析器,添加自己的解析器非常容易。

例如,这里有一个将args映射到枚举的处理程序:

 import com.martiansoftware.jsap.ParseException; import com.martiansoftware.jsap.PropertyStringParser; /* This is a StringParser implementation that maps a String to an Enum instance using Enum.valueOf() */ public class EnumStringParser extends PropertyStringParser { public Object parse(final String s) throws ParseException { try { final Class klass = Class.forName(super.getProperty("klass")); return Enum.valueOf(klass, s.toUpperCase()); } catch (ClassNotFoundException e) { throw new ParseException(super.getProperty("klass") + " could not be found on the classpath"); } } } 

而且我不喜欢通过XML进行配置编程,但是JSAP有一种非常好的方法可以在代码之外声明选项和设置,所以你的代码不会被数百行设置混乱,这些设置会混淆和模糊真正的function代码,请参阅我的链接, 了解如何使用JSAP作为示例,比我尝试的任何其他库更少的代码。

这是您的更新中阐明的问题的方向解决方案, “脚本”文件中的行仍然是命令行。 逐行从文件中读取它们并调用JSAP.parse(String);

我使用这种技术一直为Web应用程序提供“命令行”function。 一个特别的用途是在一个带有Director / Flash前端的大型多人在线游戏中,我们启用了来自聊天的“命令”,并在后端使用JSAP来解析它们并根据它解析的内容执行代码。 非常类似于您想要做的事情,除了您从文件而不是套接字读取“命令”。 我会抛弃joptsimple而只是使用JSAP,你会被它强大的可扩展性所破坏。

如果您只需要支持类UNIX操作系统,那么有一个更好的解决方案 。 与ant的Commandline不同,DrJava的ArgumentTokenizer更像是类似的:它支持转义!

说真的,甚至像sh -c 'echo "\"un'\''kno\"wn\$\$\$'\'' with \$\"\$\$. \"zzz\""'这样疯狂的东西sh -c 'echo "\"un'\''kno\"wn\$\$\$'\'' with \$\"\$\$. \"zzz\""' sh -c 'echo "\"un'\''kno\"wn\$\$\$'\'' with \$\"\$\$. \"zzz\""'被正确地标记为[bash, -c, echo "\"un'kno\"wn\$\$\$' with \$\"\$\$. \"zzz\""] (顺便说一下,当运行时,此命令输出"un'kno"wn$$$' with $"$$. "zzz" )。

 /** * [code borrowed from ant.jar] * Crack a command line. * @param toProcess the command line to process. * @return the command line broken into strings. * An empty or null toProcess parameter results in a zero sized array. */ public static String[] translateCommandline(String toProcess) { if (toProcess == null || toProcess.length() == 0) { //no command? no string return new String[0]; } // parse with a simple finite state machine final int normal = 0; final int inQuote = 1; final int inDoubleQuote = 2; int state = normal; final StringTokenizer tok = new StringTokenizer(toProcess, "\"\' ", true); final ArrayList result = new ArrayList(); final StringBuilder current = new StringBuilder(); boolean lastTokenHasBeenQuoted = false; while (tok.hasMoreTokens()) { String nextTok = tok.nextToken(); switch (state) { case inQuote: if ("\'".equals(nextTok)) { lastTokenHasBeenQuoted = true; state = normal; } else { current.append(nextTok); } break; case inDoubleQuote: if ("\"".equals(nextTok)) { lastTokenHasBeenQuoted = true; state = normal; } else { current.append(nextTok); } break; default: if ("\'".equals(nextTok)) { state = inQuote; } else if ("\"".equals(nextTok)) { state = inDoubleQuote; } else if (" ".equals(nextTok)) { if (lastTokenHasBeenQuoted || current.length() != 0) { result.add(current.toString()); current.setLength(0); } } else { current.append(nextTok); } lastTokenHasBeenQuoted = false; break; } } if (lastTokenHasBeenQuoted || current.length() != 0) { result.add(current.toString()); } if (state == inQuote || state == inDoubleQuote) { throw new RuntimeException("unbalanced quotes in " + toProcess); } return result.toArray(new String[result.size()]); } 

扩展Andreas_D的答案 ,而不是复制,使用优秀的Plexus Common Utilities库中的CommandLineUtils.translateCommandline(String toProcess)

我猜这个会帮助你:

CLI

我使用Java Getopt端口来完成它。