C#/.NET 命令行参数解析器
用于解析命令行参数并存储/检索它们的类。
引言
即使使用现代 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 的帮助。