如何像字符串一样拆分命令行?

时间:2012-11-21 14:30:51

标签: java regex

基本上,我需要将字符串拆分为

"one quoted argument" those are separate arguments "but not \"this one\""

获取参数列表

的结果
  • “一个引用的论点”
  • 那些
  • 单独的
  • “但不是\”这一个\“”

这个正则表达式"(\"|[^"])*"|[^ ]+几乎完成了这项工作,但问题是正则表达式总是(至少在java中)尝试匹配最长的字符串。

因此,当我将正则表达式应用于以带引号的参数开头和结尾的字符串时,它匹配整个字符串,并且不为每个参数创建一个组。

有没有办法调整这个正则表达式或matcherpattern或其他什么来处理它?<​​/ p>

注意:请勿告诉我,我可以使用GetOptCommandLine.parse或其他类似内容 我关注的是纯java正则表达式(如果可能的话,我怀疑它......)。

4 个答案:

答案 0 :(得分:4)

  

正则表达式总是(至少在java中)尝试匹配   最长的字符串。

嗯......不。

如果您使用贪婪或非贪婪的表达式,则由此控制。见some examples。使用非贪婪的(通过添加问号)应该这样做。它被称为lazy quantification

默认是贪婪的,但这并不意味着它总是这样。

答案 1 :(得分:4)

您可以使用非贪婪限定符*?使其正常工作:

"(\\"|[^"])*?"|[^ ]+

请参阅此链接,了解实际操作示例:http://gskinner.com/RegExr/?32srs

答案 2 :(得分:2)

public static String[] parseCommand( String cmd )
{
    if( cmd == null || cmd.length() == 0 )
    {
        return new String[]
        {};
    }

    cmd = cmd.trim();
    String regExp = "\"(\\\"|[^\"])*?\"|[^ ]+";
    Pattern pattern = Pattern.compile( regExp, Pattern.MULTILINE | Pattern.CASE_INSENSITIVE );
    Matcher matcher = pattern.matcher( cmd );
    List< String > matches = new ArrayList< String >();
    while( matcher.find() ) {
        matches.add( matcher.group() );
    }
    String[] parsedCommand = matches.toArray(new String[] {});
    return parsedCommand;
}

答案 3 :(得分:2)

我想出了这个(感谢Alex为我提供了一个很好的起点:))

/**
 * Pattern that is capable of dealing with complex command line quoting and
 * escaping. This can recognize correctly:
 * <ul>
 * <li>"double quoted strings"
 * <li>'single quoted strings'
 * <li>"escaped \"quotes within\" quoted string"
 * <li>C:\paths\like\this or "C:\path like\this"
 * <li>--arguments=like_this or "--args=like this" or '--args=like this' or
 * --args="like this" or --args='like this'
 * <li>quoted\ whitespaces\\t (spaces & tabs)
 * <li>and probably more :)
 * </ul>
 */
private static final Pattern cliCracker = Pattern
    .compile(
       "[^\\s]*\"(\\\\+\"|[^\"])*?\"|[^\\s]*'(\\\\+'|[^'])*?'|(\\\\\\s|[^\\s])+",
       Pattern.MULTILINE);