Лучший способ анализа аргументов командной строки в С#?[закрыто]

StackOverflow https://stackoverflow.com/questions/491595

  •  20-08-2019
  •  | 
  •  

Вопрос

При создании консольных приложений, принимающих параметры, вы можете использовать аргументы, передаваемые в Main(string[] args).

Раньше я просто индексировал/зацикливал этот массив и выполнял несколько регулярных выражений для извлечения значений.Однако когда команды усложняются, анализ может стать довольно уродливым.

Итак, меня интересует:

  • Библиотеки, которые вы используете
  • Шаблоны, которые вы используете

Предположим, что команды всегда соответствуют общим стандартам, таким как ответил здесь.

Это было полезно?

Решение

Я настоятельно рекомендую использовать NDesk.Параметры (Документация) и/или Моно.Параметры (тот же API, другое пространство имен).Ан пример из документации:

bool show_help = false;
List<string> names = new List<string> ();
int repeat = 1;

var p = new OptionSet () {
    { "n|name=", "the {NAME} of someone to greet.",
       v => names.Add (v) },
    { "r|repeat=", 
       "the number of {TIMES} to repeat the greeting.\n" + 
          "this must be an integer.",
        (int v) => repeat = v },
    { "v", "increase debug message verbosity",
       v => { if (v != null) ++verbosity; } },
    { "h|help",  "show this message and exit", 
       v => show_help = v != null },
};

List<string> extra;
try {
    extra = p.Parse (args);
}
catch (OptionException e) {
    Console.Write ("greet: ");
    Console.WriteLine (e.Message);
    Console.WriteLine ("Try `greet --help' for more information.");
    return;
}

Другие советы

Мне очень нравится библиотека анализатора командной строки ( http://commandline.codeplex.com/ ).Он имеет очень простой и элегантный способ настройки параметров через атрибуты:

class Options
{
    [Option("i", "input", Required = true, HelpText = "Input file to read.")]
    public string InputFile { get; set; }

    [Option(null, "length", HelpText = "The maximum number of bytes to process.")]
    public int MaximumLenght { get; set; }

    [Option("v", null, HelpText = "Print details during execution.")]
    public bool Verbose { get; set; }

    [HelpOption(HelpText = "Display this help screen.")]
    public string GetUsage()
    {
        var usage = new StringBuilder();
        usage.AppendLine("Quickstart Application 1.0");
        usage.AppendLine("Read user manual for usage instructions...");
        return usage.ToString();
    }
}

В Библиотека WPF TestApi поставляется с одним из лучших анализаторов командной строки для разработки на C#.Я настоятельно рекомендую изучить его, начиная с Блог Иво Манолова об API:

// EXAMPLE #2:
// Sample for parsing the following command-line:
// Test.exe /verbose /runId=10
// This sample declares a class in which the strongly-
// typed arguments are populated
public class CommandLineArguments
{
   bool? Verbose { get; set; }
   int? RunId { get; set; }
}

CommandLineArguments a = new CommandLineArguments();
CommandLineParser.ParseArguments(args, a);

Похоже, у каждого есть свои любимые парсеры командной строки, думаю, мне лучше добавить и свой :).

http://bizark.codeplex.com/

Эта библиотека содержит парсер командной строки это инициализирует класс значениями из командной строки.У него масса функций (я создавал их много лет).

Из документация...

Синтаксический анализ командной строки в среде BizArk имеет следующие ключевые особенности:

  • Автоматическая инициализация: Свойства класса устанавливаются автоматически на основе аргументов командной строки.
  • Свойства по умолчанию: Отправьте значение без указания имени свойства.
  • Преобразование значений: Использует мощный класс ConvertEx, также включенный в BizArk, для преобразования значений в правильный тип.
  • Логические флаги: Флаги можно указать, просто используя аргумент (например, /b для true и /b- для false) или добавив значения true/false, да/нет и т. д.
  • Массивы аргументов: Просто добавьте несколько значений после имени командной строки, чтобы задать свойство, определенное как массив.Ex, /x 1 2 3 заполнит x массивом { 1, 2, 3 } (при условии, что x определен как массив целых чисел).
  • Псевдонимы командной строки: Свойство может поддерживать несколько псевдонимов командной строки.Например, в Справке используется псевдоним ?.
  • Частичное распознавание имени: Вам не нужно указывать полное имя или псевдоним, просто напишите достаточно, чтобы синтаксический анализатор смог отличить свойство/псевдоним от других.
  • Поддерживает ClickOnce: Можно инициализировать свойства, даже если они указаны в виде строки запроса в URL-адресе для развернутых приложений ClickOnce.Метод инициализации командной строки определит, работает ли он как ClickOnce или нет, поэтому ваш код не нужно изменять при его использовании.
  • Автоматически создает /?помощь: Это включает в себя красивое форматирование, учитывающее ширину консоли.
  • Загрузить/сохранить аргументы командной строки в файл: Это особенно полезно, если у вас есть несколько больших и сложных наборов аргументов командной строки, которые вы хотите запускать несколько раз.

Некоторое время назад я написал анализатор аргументов командной строки C#.Это в: http://www.codeplex.com/CommandLineArguments

ХЛОПАТЬ В ЛАДОШИ (анализатор аргументов командной строки) имеет удобный API и прекрасно документирован.Вы создаете метод, аннотируя параметры. https://github.com/adrianaisemberg/CLAP

Существует множество решений этой проблемы.Для полноты и предоставления альтернативы, если кто-то пожелает, я добавляю этот ответ для двух полезных классов в свой библиотека кода Google.

Первый — ArgumentList, который отвечает только за анализ параметров командной строки.Он собирает пары имя-значение, определенные переключателями «/x:y» или «-x=y», а также собирает список «безымянных» записей.Это просто использование обсуждается здесь, посмотреть класс здесь.

Вторая часть этого — Командный интерпретатор который создает полнофункциональное приложение командной строки из вашего класса .Net.В качестве примера:

using CSharpTest.Net.Commands;
static class Program
{
    static void Main(string[] args)
    {
        new CommandInterpreter(new Commands()).Run(args);
    }
    //example ‘Commands’ class:
    class Commands
    {
        public int SomeValue { get; set; }
        public void DoSomething(string svalue, int ivalue)
        { ... }

С помощью приведенного выше примера кода вы можете запустить следующее:

Program.exe DoSomething «строковое значение» 5

-- или --

Program.exe делает что-то /ivalue=5 -svalue:"строковое значение"

Это настолько просто или настолько сложно, насколько вам нужно.Ты можешь просмотрите исходный код, просмотреть помощь, или скачать двоичный файл.

Мне нравится Вон тот, потому что вы можете «определить правила» для аргументов, нужны они или нет,...

или если вы разбираетесь в Unix, вам может понравиться GNU Getopt .NET порт.

Тебе может понравиться мой Rug.Cmd

Простой в использовании и расширяемый анализатор аргументов командной строки.Ручки:Логическое значение, плюс/минус, строка, список строк, CSV, перечисление.

Встроенный режим помощи '/?'.

Встроенные режимы генератора документов '/??' и '/?D'.

static void Main(string[] args) 
{            
    // create the argument parser
    ArgumentParser parser = new ArgumentParser("ArgumentExample", "Example of argument parsing");

    // create the argument for a string
    StringArgument StringArg = new StringArgument("String", "Example string argument", "This argument demonstrates string arguments");

    // add the argument to the parser 
    parser.Add("/", "String", StringArg);

    // parse arguemnts
    parser.Parse(args);

    // did the parser detect a /? argument 
    if (parser.HelpMode == false) 
    {
        // was the string argument defined 
        if (StringArg.Defined == true)
        {
            // write its value
            RC.WriteLine("String argument was defined");
            RC.WriteLine(StringArg.Value);
        }
    }
}

Редактировать:Это мой проект, и поэтому этот ответ не следует рассматривать как одобрение третьей стороны.Тем не менее, я использую его для каждой программы, основанной на командной строке, которую я пишу, это открытый исходный код, и я надеюсь, что другие смогут извлечь из него пользу.

Существует анализатор аргументов командной строки по адресу http://www.codeplex.com/commonlibrarynet

Он может анализировать аргументы, используя
1.атрибуты
2.явные вызовы
3.одна строка с несколькими аргументами ИЛИ массив строк

Он может обрабатывать такие вещи, как следующие:

-конфигурация:Ка-Дата начала:${сегодня} -область:Настройки «Нью-Йорк»01

Его очень легко использовать.

Это обработчик, который я написал на основе Novell. Options сорт.

Этот предназначен для консольных приложений, выполняющих while (input !="exit") цикл стилей, например, интерактивная консоль, такая как консоль FTP.

Пример использования:

static void Main(string[] args)
{
    // Setup
    CommandHandler handler = new CommandHandler();
    CommandOptions options = new CommandOptions();

    // Add some commands. Use the v syntax for passing arguments
    options.Add("show", handler.Show)
        .Add("connect", v => handler.Connect(v))
        .Add("dir", handler.Dir);

    // Read lines
    System.Console.Write(">");
    string input = System.Console.ReadLine();

    while (input != "quit" && input != "exit")
    {
        if (input == "cls" || input == "clear")
        {
            System.Console.Clear();
        }
        else
        {
            if (!string.IsNullOrEmpty(input))
            {
                if (options.Parse(input))
                {
                    System.Console.WriteLine(handler.OutputMessage);
                }
                else
                {
                    System.Console.WriteLine("I didn't understand that command");
                }

            }

        }

        System.Console.Write(">");
        input = System.Console.ReadLine();
    }
}

И источник:

/// <summary>
/// A class for parsing commands inside a tool. Based on Novell Options class (http://www.ndesk.org/Options).
/// </summary>
public class CommandOptions
{
    private Dictionary<string, Action<string[]>> _actions;
    private Dictionary<string, Action> _actionsNoParams;

    /// <summary>
    /// Initializes a new instance of the <see cref="CommandOptions"/> class.
    /// </summary>
    public CommandOptions()
    {
        _actions = new Dictionary<string, Action<string[]>>();
        _actionsNoParams = new Dictionary<string, Action>();
    }

    /// <summary>
    /// Adds a command option and an action to perform when the command is found.
    /// </summary>
    /// <param name="name">The name of the command.</param>
    /// <param name="action">An action delegate</param>
    /// <returns>The current CommandOptions instance.</returns>
    public CommandOptions Add(string name, Action action)
    {
        _actionsNoParams.Add(name, action);
        return this;
    }

    /// <summary>
    /// Adds a command option and an action (with parameter) to perform when the command is found.
    /// </summary>
    /// <param name="name">The name of the command.</param>
    /// <param name="action">An action delegate that has one parameter - string[] args.</param>
    /// <returns>The current CommandOptions instance.</returns>
    public CommandOptions Add(string name, Action<string[]> action)
    {
        _actions.Add(name, action);
        return this;
    }

    /// <summary>
    /// Parses the text command and calls any actions associated with the command.
    /// </summary>
    /// <param name="command">The text command, e.g "show databases"</param>
    public bool Parse(string command)
    {
        if (command.IndexOf(" ") == -1)
        {
            // No params
            foreach (string key in _actionsNoParams.Keys)
            {
                if (command == key)
                {
                    _actionsNoParams[key].Invoke();
                    return true;
                }
            }
        }
        else
        {
            // Params
            foreach (string key in _actions.Keys)
            {
                if (command.StartsWith(key) && command.Length > key.Length)
                {

                    string options = command.Substring(key.Length);
                    options = options.Trim();
                    string[] parts = options.Split(' ');
                    _actions[key].Invoke(parts);
                    return true;
                }
            }
        }

        return false;
    }
}

Мой личный фаворит http://www.codeproject.com/KB/recipes/plossum_commandline.aspx Питер Палотас:

[CommandLineManager(ApplicationName="Hello World",
    Copyright="Copyright (c) Peter Palotas")]
class Options
{
   [CommandLineOption(Description="Displays this help text")]
   public bool Help = false;

   [CommandLineOption(Description = "Specifies the input file", MinOccurs=1)]
   public string Name
   {
      get { return mName; }
      set
      {
         if (String.IsNullOrEmpty(value))
            throw new InvalidOptionValueException(
                "The name must not be empty", false);
         mName = value;
      }
   }

   private string mName;
}

Недавно я наткнулся на реализацию синтаксического анализа командной строки FubuCore. Мне она очень нравится по следующим причинам:

  • его легко использовать — хотя я не смог найти для него документации, решение FubuCore также предоставляет проект, содержащий хороший набор модульных тестов, которые говорят о функциональности больше, чем любая документация.
  • у него приятный объектно-ориентированный дизайн, нет повторения кода или других подобных вещей, которые я имел в своих приложениях для анализа командной строки.
  • это декларативно:вы в основном пишете классы для команд и наборов параметров и украшаете их атрибутами для установки различных параметров (например.имя, описание, обязательно/необязательно)
  • библиотека даже печатает красивый график использования, основанный на этих определениях.

Ниже приведен простой пример того, как это использовать.Чтобы проиллюстрировать использование, я написал простую утилиту, имеющую две команды:- add (добавляет объект в список - объект состоит из name(string), value(int) и логического флага) - list (списки всех добавленных в данный момент объектов)

Прежде всего, я написал класс Command для команды «добавить»:

[Usage("add", "Adds an object to the list")]
[CommandDescription("Add object", Name = "add")]
public class AddCommand : FubuCommand<CommandInput>
{
    public override bool Execute(CommandInput input)
    {
        State.Objects.Add(input); // add the new object to an in-memory collection

        return true;
    }
}

Эта команда принимает в качестве параметра экземпляр CommandInput, поэтому я определяю его следующим образом:

public class CommandInput
{
    [RequiredUsage("add"), Description("The name of the object to add")]
    public string ObjectName { get; set; }

    [ValidUsage("add")]
    [Description("The value of the object to add")]
    public int ObjectValue { get; set; }

    [Description("Multiply the value by -1")]
    [ValidUsage("add")]
    [FlagAlias("nv")]
    public bool NegateValueFlag { get; set; }
}

Следующая команда — «список», которая реализована следующим образом:

[Usage("list", "List the objects we have so far")]
[CommandDescription("List objects", Name = "list")]
public class ListCommand : FubuCommand<NullInput>
{
    public override bool Execute(NullInput input)
    {
        State.Objects.ForEach(Console.WriteLine);

        return false;
    }
}

Команда list не принимает параметров, поэтому я определил для этого класс NullInput:

public class NullInput { }

Теперь осталось только подключить это к методу Main(), вот так:

    static void Main(string[] args)
    {
        var factory = new CommandFactory();
        factory.RegisterCommands(typeof(Program).Assembly);

        var executor = new CommandExecutor(factory);

        executor.Execute(args);
    }

Программа работает как положено, печатая подсказки о правильном использовании, если какие-либо команды недействительны:

  ------------------------
    Available commands:
  ------------------------
     add -> Add object
    list -> List objects
  ------------------------

И пример использования команды «добавить»:

Usages for 'add' (Add object)
  add <objectname> [-nv]

  -------------------------------------------------
    Arguments
  -------------------------------------------------
     objectname -> The name of the object to add
    objectvalue -> The value of the object to add
  -------------------------------------------------

  -------------------------------------
    Flags
  -------------------------------------
    [-nv] -> Multiply the value by -1
  -------------------------------------

Командлеты Powershell.

Анализ, выполняемый PowerShell на основе атрибутов, указанных в командлетах, поддержка проверок, наборов параметров, конвейерная обработка, отчеты об ошибках, справка и, что самое важное, возврат объектов .NET для использования в других командлетах.

Пара ссылок, которые я нашел полезными для начала:

С# интерфейс командной строки — это очень простая библиотека анализа аргументов командной строки, которую я написал.Он хорошо документирован и имеет открытый исходный код.

Анализатор командной строки Чингисхана может быть, немного устаревший, но он очень функционален и работает очень хорошо для меня.

Я бы предложил библиотеку с открытым исходным кодом CSharpOptParse.Он анализирует командную строку и объединяет пользовательский объект .NET с вводом командной строки.Я всегда обращаюсь к этой библиотеке при написании консольного приложения на C#.

Используйте порт .net API-интерфейса Apache Commons Cli.Это прекрасно работает.

http://sourceforge.net/projects/dotnetcli/

и оригинальный API для концепций и введения

http://commons.apache.org/cli/

Очень простой и удобный в использовании специальный класс для анализа командной строки, который поддерживает аргументы по умолчанию.

class CommandLineArgs
{
    public static CommandLineArgs I
    {
        get
        {
            return m_instance;
        }
    }

    public  string argAsString( string argName )
    {
        if (m_args.ContainsKey(argName)) {
            return m_args[argName];
        }
        else return "";
    }

    public long argAsLong(string argName)
    {
        if (m_args.ContainsKey(argName))
        {
            return Convert.ToInt64(m_args[argName]);
        }
        else return 0;
    }

    public double argAsDouble(string argName)
    {
        if (m_args.ContainsKey(argName))
        {
            return Convert.ToDouble(m_args[argName]);
        }
        else return 0;
    }

    public void parseArgs(string[] args, string defaultArgs )
    {
        m_args = new Dictionary<string, string>();
        parseDefaults(defaultArgs );

        foreach (string arg in args)
        {
            string[] words = arg.Split('=');
            m_args[words[0]] = words[1];
        }
    }

    private void parseDefaults(string defaultArgs )
    {
        if ( defaultArgs == "" ) return;
        string[] args = defaultArgs.Split(';');

        foreach (string arg in args)
        {
            string[] words = arg.Split('=');
            m_args[words[0]] = words[1];
        }
    }

    private Dictionary<string, string> m_args = null;
    static readonly CommandLineArgs m_instance = new CommandLineArgs();
}

class Program
{
    static void Main(string[] args)
    {
        CommandLineArgs.I.parseArgs(args, "myStringArg=defaultVal;someLong=12");
        Console.WriteLine("Arg myStringArg  : '{0}' ", CommandLineArgs.I.argAsString("myStringArg"));
        Console.WriteLine("Arg someLong     : '{0}' ", CommandLineArgs.I.argAsLong("someLong"));
    }
}
Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top