C#でコマンドライン引数を解析する最良の方法は?[閉まっている]
-
20-08-2019 - |
質問
パラメーターを受け取るコンソール アプリケーションを構築する場合、に渡される引数を使用できます。 Main(string[] args)
.
以前は、その配列にインデックスを付けてループし、いくつかの正規表現を実行して値を抽出していました。ただし、コマンドが複雑になると、解析が非常に困難になる可能性があります。
それで私は次のことに興味があります:
- 使用するライブラリ
- 使用するパターン
コマンドは常に次のような共通標準に準拠していると想定します。 ここで答えました.
解決
私は強く NDesk.Options を(使用してお勧めします<のhref = "のhttp:// WWW。 ndesk.org/doc/ndesk-options/ "のrel = "noreferrer">ドキュメントの)および/または<のhref =" https://github.com/mono/mono/blob/master/mcs/class /Mono.Options/Mono.Options/Options.cs」のrel = "noreferrer"> Mono.Options を(同じ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#の開発のための素敵なコマンドラインパーサの1が付属しています。私は非常にAPIのイヴォManolovのブログから、それに探してお勧めします>
// 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);
誰もが独自のコマンドライン パーサーを持っているようです。私も自分のものを追加した方がよいと思います :)。
このライブラリには、 コマンドラインパーサー コマンドラインからの値を使用してクラスを初期化します。たくさんの機能があります (私は何年にもわたって構築してきました)。
から ドキュメンテーション...
BizArk フレームワークのコマンドライン解析には、次の重要な機能があります。
- 自動初期化: クラスのプロパティは、コマンドライン引数に基づいて自動的に設定されます。
- デフォルトのプロパティ: プロパティ名を指定せずに値を送信します。
- 値の変換: BizArk にも含まれている強力な ConvertEx クラスを使用して、値を適切な型に変換します。
- ブール値フラグ: フラグは、単純に引数 (例: true の場合は /b、false の場合は /b-) を使用するか、true/false、yes/no などの値を追加することによって指定できます。
- 引数配列: コマンドライン名の後に複数の値を追加するだけで、配列として定義されたプロパティを設定できます。たとえば、 /x 1 2 3 は、x に配列 { 1, 2, 3 } を設定します (x が整数の配列として定義されていると仮定します)。
- コマンドラインエイリアス: プロパティは複数のコマンドライン エイリアスをサポートできます。たとえば、ヘルプではエイリアス ? が使用されます。
- 部分的な名前認識: 完全な名前やエイリアスを詳しく説明する必要はありません。パーサーがプロパティ/エイリアスを他のプロパティと区別できる程度に入力するだけで十分です。
- ClickOnce のサポート: ClickOnce デプロイされたアプリケーションの URL でクエリ文字列として指定されている場合でも、プロパティを初期化できます。コマンドラインの初期化メソッドは、ClickOnce として実行されているかどうかを検出するため、使用時にコードを変更する必要はありません。
- /? を自動的に作成します。ヘルプ: これには、コンソールの幅を考慮した適切な書式設定が含まれます。
- コマンドライン引数をファイルにロード/保存します。 これは、複数回実行する大規模で複雑なコマンド ライン引数のセットがある場合に特に便利です。
私はしばらく前にC#のコマンドライン引数パーサを書きました。その時: http://www.codeplex.com/CommandLineArgumentsする
CLAPする(コマンドライン引数パーサ)が使用可能なAPIを有しており、見事に文書化されています。あなたはパラメータに注釈を付ける、方法を作ります。 https://github.com/adrianaisemberg/CLAPする
この問題には数多くの解決策があります。完全を期すため、そして誰かが望む場合に代替手段を提供するために、私の 2 つの有用なクラスにこの回答を追加しています。 Googleコードライブラリ.
1 つ目は ArgumentList で、コマンド ライン パラメーターの解析のみを担当します。スイッチ「/x:y」または「-x=y」で定義された名前と値のペアを収集し、「名前のない」エントリのリストも収集します。基本的なことです 使用法についてはここで説明します, ここでクラスをご覧ください.
この第 2 の部分は、 コマンドインタープリター これにより、.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:"文字列値"
必要に応じて単純にすることも、複雑にすることもできます。あなたはできる ソースコードをレビューする, ヘルプを見る, 、 または バイナリをダウンロードする.
私は、その1 のが好き引数、必要かどうか、...
またはあなたがUnixの男なら、あなたは GNU Getoptの.NET のポートます。
あなたが好きなことがあり、私の1 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.複数の引数の 1 行または文字列配列
次のようなことを処理できます。
-構成:Qa -開始日:${今日} -地域:「ニューヨーク」設定01
使い方はとても簡単です。
これは、私は、NovellのOptions
クラスに基づいて書いたハンドラです。
この一つは、例えばFTPコンソールとしてwhile (input !="exit")
スタイルのループ、対話型コンソールを実行するコンソールアプリケーションを目的としている。
使用例:
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/ですピーターPalotasによってを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 ソリューションには、どのドキュメントよりも機能について詳しく説明する素晴らしい単体テストのセットを含むプロジェクトも提供されています。
- 優れたオブジェクト指向設計を採用しており、コマンドライン解析アプリで使用していたコードの繰り返しなどはありません。
- それは宣言的です:基本的には、コマンドとパラメータのセットのクラスを作成し、それらを属性で修飾してさまざまなオプションを設定します(例:名前、説明、必須/オプション)
- ライブラリは、これらの定義に基づいて、優れた使用状況グラフも出力します。
以下は、これを使用する方法の簡単な例です。使用法を説明するために、2 つのコマンドを含む単純なユーティリティを作成しました。- 追加(オブジェクトをリストに追加します - オブジェクトは名前(文字列)、値(int)、ブールフラグで構成されます) - リスト(現在追加されているすべてのオブジェクトをすべてリスト)
まず、「add」コマンドの 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; }
}
次のコマンドは「list」で、次のように実装されます。
[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
------------------------
「add」コマンドの使用例:
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 オブジェクトの返し。
始めるにあたって役立つと思われるいくつかのリンク:
C#CLI に私が書いたライブラリを解析する非常に単純なコマンドライン引数です。それは十分に文書化し、オープンソースです。
チンギスコマンドラインパーサには少し古くなっている可能性があり、それは非常にあります完全な備えていますし、私のためにかなりうまく動作します。
私は、オープンソースのライブラリ CSharpOptParse にお勧めします。これは、コマンドラインを解析し、コマンドライン入力と、ユーザー定義の.NETオブジェクトを水和。 C#コンソールアプリケーションを書くとき、私はいつもこのライブラリに入れます。
ApacheのコモンズのCLI APIの.NETポートを使用してください。これは素晴らしい作品ます。
http://sourceforge.net/projects/dotnetcli/する
や概念および導入のためのオリジナルのAPI
簡単に、非常に単純なコマンドラインの解析のためのアドホッククラスを使用するように、それがデフォルト引数をサポートしています。
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"));
}
}