繁体   English   中英

如何解析命令行参数

[英]How to parse command line arguments

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

-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是文件路径(甚至引用)时, \\会导致解析器将所有内容放到右边。 我已经通过覆盖我自己继承自NDesk.Options.OptionSet自己的OptionSet类的parse方法来解决这个NDesk.Options.OptionSet ,但我想知道是否有任何库可以NDesk.Options.OptionSet处理这种功能?

UPDATE

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

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

它们都会因OptionException Error: Found 3 option values when expecting 2.失败OptionException Error: Found 3 option values when expecting 2.

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

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

为了解决这个问题,你只需修改-s选项定义,只考虑=作为有效的分隔符,写成"s={=}"而不是"s="

原来的答案 ,当它是关于反斜杠。

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

这是我的示例程序:

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是布尔标志值。

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

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

-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"

这里有一些解析确实会产生另一个值得一提的结果:

-sGreeting=Hello\My World -- // This gives Greeting="Hello\My" 

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

我成功使用了Command Line Parser Library一段时间了。 工作得很好,很简单, 并且允许带引号的路径

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

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 这里页面甚至有一个编码范例使用的结束)。

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

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

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

然后将字符串拆分成组

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

而不是提取你需要的信息

var pairs = groups["keyvaluepair"].Captures.Cast<Capture>() 
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);

        }
    }

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM