如何解析命令行参数

时间:2013-04-19 09:13:38

标签: c# command-line

我想解析一组看起来像这样的命令行参数:

-p[project file path] -s[name 1]=[value 1] ... -s[name n]=[value n]

只有一个项目p和任意数量的设置s

我尝试过使用NDesk.Options

var set = new OptionSet {
    { "p=", "the project file", v => { /* do stuff */ } },
    { "s=", "a setting", (m, v) =>  { /* do stuff */ } },
};

,这在大多数情况下运行良好,但当value是文件路径(甚至引用)时,\会导致解析器将所有内容放到右侧。我通过覆盖我自己从OptionSet继承的NDesk.Options.OptionSet类的解析方法来解决这个问题,但是我想知道是否有任何库可以处理这种功能。盒子?

更新

对不起它不是\我认为它是:无论如何一组失败的例子是:

-sSetting=C:\Temp
-sSetting="C:\Temp"
-s"Setting=C:\Temp"

它们都以OptionException Error: Found 3 option values when expecting 2.

失败

5 个答案:

答案 0 :(得分:5)

更新:更新以处理设置值中的冒号。

好的,所以在这里你遇到了NDesk.Options的隐式默认值之一,即在多值参数中,:=都被视为值分隔符,这意味着{ {1}}解析为3个值(Setting,C,\ Path)而不是预期的两个值。

为了解决这个问题,您只需修改Setting=C:\Path选项定义,仅将-s视为有效的分隔符,方法是编写=而不是"s={=}"

原始回答,当涉及反斜杠时。

我使用了NDesk.Options,没有遇到引用路径和反斜杠的任何问题。

这是我的示例程序:

"s="

您将看到定义与我的定义之间存在差异:public static void Main(string[] args) { string parsedPath = null; Dictionary<string, string> parsedValues = new Dictionary<string, string>(); var set = new OptionSet() { { "p=", "the project path", v => parsedPath = v }, { "s=", "a setting", (m, v) => { parsedValues.Add(m, v); } }, }; set.Parse(args); Console.WriteLine(parsedPath ?? "<NULL>"); foreach (var keyValuePair in parsedValues) { Console.WriteLine(keyValuePair.Key + "::::" + keyValuePair.Value); } } 表示该选项具有必需值,而您的定义意味着p=是布尔标志值。

在p设置或s设置中,我没有遇到任何有关反斜杠的问题。您是否可以尝试运行NDesk.Options版本0.2.1的程序并显示哪些值失败?

以下是我运行的一些示例,这些示例都已成功解析:

p

以下是一些产生另一个值得一提的结果的解析:

-p=..\Path
-p..\Path
-pC:\Hello
-pHello\World
-p"Hello\World"
-s"Greeting=Hello\World"
-sGreeting="Hello\World"
-sGreeting=Hello\World
-sGreeting="Hello\My World"
-s"Greeting=Hello\My World"

注意:如果这改变了什么,我在项目中使用Options.cs源代码文件运行NDesk.Options,而不是使用已编译的DLL。

答案 1 :(得分:3)

我成功使用了Command Line Parser Library一段时间了。效果很好,很简单,and paths with quotes are allowed

答案 2 :(得分:2)

如果您使用以下内容,则会为您完成所有拆分:

public static void Main(string[] args)
   {
       List<string> Settings = new list
       Console.WriteLine("parameter qty = {0}", args.Length);
       for(int i = 0; i < args.Length; i++)
       {
           Console.WriteLine("Arg[{0}] = [{1}]", i, args[i]);
       }

之后,一组简单的ifs就足以让您根据每个参数获得所需的操作。您可以迭代参数数组中的每个参数,以根据您的喜好使用字符串匹配或正则表达式来查看它们符合的arg。 对于eaxmple,您可以在for循环中添加一些代码:

public static void Main(string[] args)
   {
       List<string> Settings = new List<string>();
       Console.WriteLine("parameter qty = {0}", args.Length);
       for(int i = 0; i < args.Length; i++)
       {
           Console.WriteLine("Arg[{0}] = [{1}]", i, args[i]);
           if (i>0)
               {
                   // this gives you a nice iterable list of settings
                   Setting.Add(args[i]);
               }
       }
       foreach(string setting in Settings)
           {
               //do the desired action
           }
    }

附录:但是,这只会提供基本功能(如果像我一样,你来自C ++并且必须自己做事,从C#开发人员的角度来看不是很好)我现在意识到,你需要自己处理变体命令的解析(如注释/p--p or /Project= -Project=中所提到的,变体都需要在你编写的代码中处理)。但是对于开箱即用的解决方案,我建议:Ndesk.OptionsMono.Options两者的工作方式类似,如果可移植性很重要,我会倾向于Mono.Options。

在使用中,您可以将代码更改为

var set = new OptionSet {
    { "p=|project=", "the project file", v => { /* do stuff */ } },
    { "s=|setting=", "a setting", (m, v) =>  { /* do stuff */ } },
};

这应该可以为您提供所需的功能(例如,页面末尾的ndesk here甚至可以使用编码示例)。

希望这比我之前给你的答案更有用。

答案 3 :(得分:0)

您可以在一个字符串中加入所有参数,然后可以使用正则表达式:

((?<SkeyvaluePair>-s(?<key>[^=]+)\s*=\s*(?<value>[^-]+))|(?<PkeyvaluePair>-p(?<Pvalue>[^-]+)))*

然后将字符串分成组

var groups = new Regex(yourRegex).Match(message).Groups;

并提取您需要的信息

var pairs = groups["keyvaluepair"].Captures.Cast<Capture>() 

答案 4 :(得分:0)

class Program
    {
        static void Main(string[] args)
        {
            string cmd = "car.exe -ip 1.18.4.156 -port 123";
            string hostname = "localhost";
            string port = "5505";

            string[] array = cmd.Split(' ');

            int hostnameIndex = Array.FindIndex(array, key => key == "-ip");
            int portIndex = Array.FindLastIndex(array, key => key == "-port");

            if (hostnameIndex != -1)
            {
                hostname = array[hostnameIndex + 1];
            }

            if (portIndex != -1)
            {
                port = array[portIndex + 1];
            }

            Console.WriteLine("ip :" + hostname);
            Console.WriteLine("port :" + port);

        }
    }