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

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

starIconstarIconstarIconstarIcon
emptyStarIcon
starIcon

4.72/5 (14投票s)

2010年9月8日

CPOL

2分钟阅读

viewsIcon

37979

downloadIcon

692

本文介绍了一个灵活的命令行解析器,支持 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));
                }
            }
        }
    }
}

结论

我想通过重申上面的免责声明来结束:我知道已经有其他解决方案提供相同的功能。我的解决方案不一定添加任何新内容或改进。我只是想分享我拥有的这段旧代码。话虽如此,我希望你觉得它在某种程度上有用或有趣。

© . All rights reserved.