适用于 .NET 的高级命令行解析器类






4.72/5 (14投票s)
本文介绍了一个灵活的命令行解析器,支持 Windows 和 Unix 风格的参数格式。
引言
在开发 DocktorUI 库的停靠框架时,我发现代码中的一部分,虽然在某些情况下很有用,但实际上已经过时,并且完全超出了项目的范围,与项目的其余部分不太协调。所以我决定删除它,但考虑到它可能对某些人有用,与其丢弃它,不如将其提供给那些少数人。这段代码由一组 C# 类组成,用于通用的应用程序启动控制。一些类旨在通过使用 Windows 命名管道进行 IPC(进程间通信),而另一个类则专门用于解析 Windows 或 Unix 风格的命令行。我决定只提供后者,因为命名管道现在由 .NET 3.5 处理,因此我的 IPC 代码或多或少已经过时了。
背景
我知道还有其他选项提供类似的功能。我并不声称这个更好或更完整,我也猜它没有引入任何新东西。我没有检查过其他的,所以甚至无法告知。我已经有了这段代码,所以只是将其公开。希望它对某人有用。
使用代码
CommandLine
类允许应用程序内置复杂的命令行解析。请记住,这段代码实际上并没有在生产环境中使用过,所以可能存在一些缺陷。该类使用起来非常简单,并且有详细的注释。
CommandLine cmdLine = new CommandLine(args);
String arg = cmdLine["name"];
我认为代码本身就很容易理解。你可以使用参数列表或包含整个命令行的字符串来实例化该类。解析是内联完成的,使用语法分析,类似于生成的词法分析器所做的那样。这使得添加/更改功能更容易,至少在我看来是这样。注释中也有一份等效语法的草稿。虽然这只是一个指导模型,但它实际上并没有用于生成解析代码。这里是提到的语法
/// Grammar
///
/// parameters : parameter*
/// ;
///
/// parameter : '/' parameter-struct
/// | '--' parameter-struct
/// | '-' parameter-struct
/// ;
///
/// parameter-struct : parameter-name (parameter-separator parameter-value)? ;
///
/// parameter-name : parameter-name-char+ ;
///
/// parameter-separator : ':'
/// | '='
/// | ' '
/// ;
///
/// parameter-value : '\'' (ANY LESS '\'')* '\''
/// | '"' (ANY LESS '"')* '"'
/// | (parameter-value-first-char parameter-value-char*)?
/// ;
///
/// parameter-name-char : ANY LESS ' ', ':', '=' ;
///
/// parameter-value-first-char : ANY LESS ' ', '/', ':', '=' ;
///
/// parameter-value-char : ANY LESS ' ' ;
///
///
/// Matches:
///
/// Application.exe /new /parm: "A parameter can be '/parm:
/// '/value:''" /parm2: value2 /parm3: "value3: 'the value'"
这是完整的演示应用程序代码,可能可以更清楚地了解该类提供的功能
using System;
using System.Collections.Generic;
using System.Text;
using StartUp;
namespace CommandLineDemo
{
class Program
{
static void Main(string[] args)
{
CommandLine cmdLine = new CommandLine(args);
PrintCommandLine(cmdLine);
Console.WriteLine("Insert Command Line to parse or Return to exit.");
String cmd = Console.ReadLine();
while (!String.IsNullOrEmpty(cmd))
{
cmdLine.ParametersString = cmd;
PrintCommandLine(cmdLine);
cmd = Console.ReadLine();
}
}
static void PrintCommandLine(CommandLine cmdLine)
{
String cmd = cmdLine.ParametersString;
IDictionary<String, String> args = cmdLine.Parameters;
if (!String.IsNullOrEmpty(cmd))
{
if (cmdLine.Success)
{
Console.WriteLine("Command Line parsed successfully. Result:");
foreach (String key in args.Keys)
{
Console.WriteLine("\"{0}\" => \"{1}\"", key, args[key]);
}
}
else
{
Console.WriteLine("Error while parsing Command Line. " +
"Position marked with <---:");
int offset = cmdLine.ErrorOffset + 1;
Console.WriteLine("{0}<---{1}",
cmd.Substring(0, offset), cmd.Substring(offset));
}
}
}
}
}
结论
我想通过重申上面的免责声明来结束:我知道已经有其他解决方案提供相同的功能。我的解决方案不一定添加任何新内容或改进。我只是想分享我拥有的这段旧代码。话虽如此,我希望你觉得它在某种程度上有用或有趣。