65.9K
CodeProject 正在变化。 阅读更多。
Home

C#/.NET 命令行参数解析器

starIconstarIconstarIconstarIcon
emptyStarIcon
starIcon

4.91/5 (101投票s)

2002年10月28日

MIT

3分钟阅读

viewsIcon

887957

downloadIcon

8497

用于解析命令行参数并存储/检索它们的类。

引言

即使使用现代 UI,我们经常需要一种方法来使用特定参数启动我们的程序。 命令行参数有助于提供这些参数,而无需将它们暴露给所有人。 使用 .NET 和 C# 开发时,您可以从 `Main(string[] Args)` 函数获取命令行参数。 `Args` 实际上是一个数组,其中包含命令行中输入的所有用空格分隔的字符串。 以下类所做的是将这个字符串数组转换为一个可以随时使用的键/值对集合。 然后,您可以轻松地从该集合中查找并获取参数(键)的特定值。

Arguments 类

此类解析您的命令行参数,查找所有以 **-**、**--** 或 **/** 开头的参数以及所有链接的值。 我假设值可以用**空格**、**:** 或 **=** 与参数分隔。 解析器还会查找诸如 **'** 或 **"** 之类的括起来的字符并将其删除。 当然,如果您有一个像 `‘Mike's house’` 这样的值,则只会删除第一个和最后一个 **'**。 为了实现其目标,该类在很大程度上依赖于 .NET 的正则表达式功能。 第一个正则表达式 (^-{1,2}|^/|=|:) 将一个参数分成几个部分

  • 参数

此正则表达式处理仅存在参数、仅存在值或两者都存在的情况。 程序根据找到的部分数量执行相应的操作。 第二个正则表达式 (^['"]?(.*?)['"]?$) 用于检测并删除值中所有开头和结尾的 **'** 或 **"** 字符。 解析完所有参数后,从参数中检索值就像编写 `MyValue=params["MyParam"]` 一样简单。 如果该参数不存在或不在命令行中,那么您将获得一个可以测试的 `null` 引用。

using System;
using System.Collections.Specialized;
using System.Text.RegularExpressions;

namespace CommandLine.Utility
{
    /// <summary>
    /// Arguments class
    /// </summary>
    public class Arguments{
        // Variables
        private StringDictionary Parameters;

        // Constructor
        public Arguments(string[] Args)
        {
            Parameters = new StringDictionary();
            Regex Spliter = new Regex(@"^-{1,2}|^/|=|:",
                RegexOptions.IgnoreCase|RegexOptions.Compiled);

            Regex Remover = new Regex(@"^['""]?(.*?)['""]?$",
                RegexOptions.IgnoreCase|RegexOptions.Compiled);

            string Parameter = null;
            string[] Parts;

            // Valid parameters forms:
            // {-,/,--}param{ ,=,:}((",')value(",'))
            // Examples: 
            // -param1 value1 --param2 /param3:"Test-:-work" 
            //   /param4=happy -param5 '--=nice=--'
            foreach(string Txt in Args)
            {
                // Look for new parameters (-,/ or --) and a
                // possible enclosed value (=,:)
                Parts = Spliter.Split(Txt,3);

                switch(Parts.Length){
                // Found a value (for the last parameter 
                // found (space separator))
                case 1:
                    if(Parameter != null)
                    {
                        if(!Parameters.ContainsKey(Parameter)) 
                        {
                            Parts[0] = 
                                Remover.Replace(Parts[0], "$1");

                            Parameters.Add(Parameter, Parts[0]);
                        }
                        Parameter=null;
                    }
                    // else Error: no parameter waiting for a value (skipped)
                    break;

                // Found just a parameter
                case 2:
                    // The last parameter is still waiting. 
                    // With no value, set it to true.
                    if(Parameter!=null)
                    {
                        if(!Parameters.ContainsKey(Parameter)) 
                            Parameters.Add(Parameter, "true");
                    }
                    Parameter=Parts[1];
                    break;

                // Parameter with enclosed value
                case 3:
                    // The last parameter is still waiting. 
                    // With no value, set it to true.
                    if(Parameter != null)
                    {
                        if(!Parameters.ContainsKey(Parameter)) 
                            Parameters.Add(Parameter, "true");
                    }

                    Parameter = Parts[1];

                    // Remove possible enclosing characters (",')
                    if(!Parameters.ContainsKey(Parameter))
                    {
                        Parts[2] = Remover.Replace(Parts[2], "$1");
                        Parameters.Add(Parameter, Parts[2]);
                    }

                    Parameter=null;
                    break;
                }
            }
            // In case a parameter is still waiting
            if(Parameter != null)
            {
                if(!Parameters.ContainsKey(Parameter)) 
                    Parameters.Add(Parameter, "true");
            }
        }

        // Retrieve a parameter value if it exists 
        // (overriding C# indexer property)
        public string this [string Param]
        {
            get
            {
                return(Parameters[Param]);
            }
        }
    }
}

测试类

这是一个如何使用 `Arguments` 类的例子。 像往常一样,代码可以在 zip 文件中找到。

using System;
using CommandLine.Utility;

namespace CommandLine
{
    /// <summary>
    /// Testing class
    /// </summary>
    class Test
    {
        /// <summary>
        /// Main loop
        /// </summary>
        [STAThread]
        static void Main(string[] Args)
        {
        // Command line parsing
        Arguments CommandLine=new Arguments(Args);

        // Look for specific arguments values and display 
        // them if they exist (return null if they don't)
        if(CommandLine["param1"] != null) 
            Console.WriteLine("Param1 value: " + 
                CommandLine["param1"]);
        else
            Console.WriteLine("Param1 not defined !");

        if(CommandLine["height"] != null) 
            Console.WriteLine("Height value: " + 
                CommandLine["height"]);
        else 
            Console.WriteLine("Height not defined !");

        if(CommandLine["width"] != null) 
            Console.WriteLine("Width value: " + 
                CommandLine["width"]);
        else 
            Console.WriteLine("Width not defined !");

        if(CommandLine["size"] != null) 
            Console.WriteLine("Size value: " + 
                CommandLine["size"]);
        else 
            Console.WriteLine("Size not defined !");

        if(CommandLine["debug"] != null) 
            Console.WriteLine("Debug value: " + 
                CommandLine["debug"]);
        else 
            Console.WriteLine("Debug not defined !");

        // Wait for key
        Console.Out.WriteLine("Arguments parsed. Press a key");
        Console.Read();
        }
    }
}

执行示例

我在 ZIP 文件中包含的 Visual Studio .NET 解决方案的属性对话框中,将以下命令行作为 Arguments 设置提供:-size=100 /height:'400' -param1 "Nice stuff !" --debug 该命令行产生以下输出

Param1 value: Nice stuff !
Height value: 400
Width not defined !
Size value: 100
Debug value: true
Arguments parsed. Press a key...

结论

在这篇文章中,我们看到了如何解析、存储和检索 .NET 应用程序的参数行。 这个类足够通用,可以处理很多不同类型的参数。 与我们习惯的大多数形式兼容(`-param`、`--param` 或 Windows `/param`)。 感谢正则表达式。 使用正则表达式使我们能够保持 `Arguments` 类非常小,并且用法非常简单。 正则表达式非常强大,可用于满足您的大部分解析需求(只要速度不是主要问题)。

特别感谢:Benjamin、Guillaume 和 Sebastien 的支持 :o)

祝你编码愉快!!!

历史

  • 2002 年 10 月 28 日 - v1.0 首次发布
  • 2002 年 11 月 6 日 - v1.1 Bug 修复。 现在应该没有 Bug 了。 感谢 n2s 的帮助。
© . All rights reserved.