50

コマンドラインから実行可能なプログラムを作成している場合は、多くの場合、複数のオプションまたはフラグと、場合によっては複数の引数をユーザーに提供する必要があります。私はこれを何度も経験しましたが、引数をループして適切なハンドラー関数を呼び出すためのある種のデザインパターンはありますか?

検討:

myprogram -f filename -d directory -r regex

言語に組み込まれているものを使用して引数を取得した後、ハンドラー関数をどのように編成しますか?(言語固有の回答を歓迎します。それが回答を明確にするのに役立つ場合)

4

15 に答える 15

17

次の答えは、あなたが探しているものに沿っていると思います:

テンプレート パターンの適用を検討する必要があります (「デザイン パターン」のテンプレート メソッド [Gamma, el al])。

要するに、全体的な処理は次のようになります。

If the arguments to the program are valid then
    Do necessary pre-processing
    For every line in the input
        Do necessary input processing
    Do necessary post-processing
Otherwise
    Show the user a friendly usage message

つまり、次のメソッドを持つ ConsoleEngineBase クラスを実装します。

PreProcess()
ProcessLine()
PostProcess()
Usage()
Main()

次に、ConsoleEngine() インスタンスをインスタンス化し、Main() メッセージを送信して開始するシャーシを作成します。

これをコンソールまたはコマンド ライン プログラムに適用する方法の良い例については、次のリンクを参照してください: http://msdn.microsoft.com/en-us/magazine/cc164014.aspx

例は C# ですが、アイデアは他の環境でも簡単に実装できます。

GetOpt() は、引数の処理 (前処理) に適合する部分だけと見なすことができます。

お役に立てれば。

于 2011-09-23T13:45:56.650 に答える
14

処理のための文書化された「パターン」を知りません。

引数を処理するための最も古いライブラリ/APIの1つはgetoptだと思います。「getopt」をグーグルで検索すると、多くのマニュアルページと実装へのリンクが表示されます。

一般に、私のアプリケーションには、引数プロセッサが通信する方法を知っている設定または設定サービスがあります。次に、引数は、アプリケーションが照会するよりも、このサービス内の何かに変換されます。これは、設定の辞書(「filename」という名前の文字列設定など)のように単純な場合があります。

于 2008-09-10T15:41:59.793 に答える
6

言語については言及していませんが、Javaの場合はApacheCommonsCLIが大好きです。C / C ++の場合、getopt。

于 2008-09-10T15:44:19.270 に答える
5

まあ、それは古い投稿ですが、私はまだ貢献したいと思います. 質問は設計パターンの選択に関するものでしたが、どのライブラリを使用するかについて多くの議論が見られました。使用するテンプレート デザイン パターンについて説明している lindsay に従って、マイクロソフトのリンクをチェックアウトしました。

しかし、私は投稿に納得していません。テンプレート パターンの目的は、さまざまな他のクラスによって実装されるテンプレートを定義して、統一された動作をさせることです。コマンドラインの解析はそれに適合しないと思います。

私はむしろ「コマンド」デザインパターンを使いたいです。このパターンは、メニュー駆動のオプションに最適です。

http://www.blackwasp.co.uk/Command.aspx

したがって、あなたの場合、-f、-d、および-rはすべて、共通または個別のレシーバーが定義されたコマンドになります。そうすれば、将来さらに多くの受信者を定義できます。次のステップは、処理チェーンが必要な場合に備えて、これらのコマンドの責任をチェーン化することです。私が選ぶだろう。

http://www.blackwasp.co.uk/ChainOfResponsibility.aspx

これら 2 つの組み合わせは、コマンド ライン処理またはメニュー駆動型アプローチのコードを整理するのに最適だと思います。

于 2014-05-10T16:04:36.897 に答える
4

これについてのいくつかのコメント...

第 1 に、それ自体にはパターンはありませんが、パーサーを作成することは本質的に機械的な作業です。文法が与えられれば、パーサーは簡単に生成できるからです。Bison や ANTLR などのツールが思い浮かびます。

とは言っても、パーサー ジェネレーターは通常、コマンド ラインには過剰です。したがって、通常のパターンは、退屈な詳細を処理するのにうんざりし、それを行うライブラリを見つけるまで、(他の人が示したように) 自分で数回作成することです。

getopt が与える多くの労力を節約し、テンプレートをうまく利用する C++ 用のコードを作成しました。TCLAP

于 2008-09-16T22:39:52.187 に答える
2

「-ttext」や「-i44」などのオプションが好きです。「-fname」や「--very-long-argument=some_value」は好きではありません。

また、「-?」、「-h」、「/h」はすべてヘルプ画面を表示します。

これが私のコードがどのように見えるかです:

int main (int argc, char *argv[])
   {  int i;
      char *Arg;
      int ParamX, ParamY;
      char *Text, *Primary;

   // Initialize...
   ParamX = 1;
   ParamY = 0;
   Text = NULL;
   Primary = NULL;

   // For each argument...
   for (i = 0; i < argc; i++)
      {
      // Get the next argument and see what it is
      Arg = argv[i];
      switch (Arg[0])
         {
         case '-':
         case '/':
            // It's an argument; which one?
            switch (Arg[1])
               {
               case '?':
               case 'h':
               case 'H':
                  // A cry for help
                  printf ("Usage:  whatever...\n\n");
                  return (0);
                  break;

               case 't':
               case 'T':
                  // Param T requires a value; is it there?
                  i++;
                  if (i >= argc)
                     {
                     printf ("Error:  missing value after '%s'.\n\n", Arg);
                     return (1);
                     }

                  // Just remember this
                  Text = Arg;

                  break;

               case 'x':
               case 'X':
                  // Param X requires a value; is it there?
                  i++;
                  if (i >= argc)
                     {
                     printf ("Error:  missing value after '%s'.\n\n", Arg);
                     return (1);
                     }

                  // The value is there; get it and convert it to an int (1..10)
                  Arg = argv[i];
                  ParamX = atoi (Arg);
                  if ((ParamX == 0) || (ParamX > 10))
                     {
                     printf ("Error:  invalid value for '%s'; must be between 1 and 10.\n\n", Arg);
                     return (1);
                     }

                  break;

               case 'y':
               case 'Y':
                  // Param Y doesn't expect a value after it
                  ParamY = 1;
                  break;

               default:
                  // Unexpected argument
                  printf ("Error:  unexpected parameter '%s'; type 'command -?' for help.\n\n", Arg);
                  return (1);
                  break;
               }

            break;

         default:
            // It's not a switch that begins with '-' or '/', so it's the primary option
            Primary = Arg;

            break;
         }
      }

   // Done
   return (0);
   }
于 2008-09-10T18:04:59.463 に答える
2

フラグを使用してセットアップすることを目的とした「config」オブジェクトと、コマンドラインの解析を処理し、オプションの一定のストリームを提供する適切なコマンドラインパーサーがあると仮定すると、ここに擬似コードのブロックがあります。

while (current_argument = cli_parser_next()) {
    switch(current_argument) {
        case "f": //Parser strips the dashes
        case "force":
            config->force = true;
            break;
        case "d":
        case "delete":
            config->delete = true;
            break;
        //So on and so forth
        default:
            printUsage();
            exit;
    }
}
于 2008-09-10T16:57:41.887 に答える
2

mes5kによるANTLRの回答をリフしています。Codeproject へのこのリンクは、ANLTR と、訪問パターンを使用してアプリに実行させたいアクションを実装する方法について説明する記事です。よく書かれており、レビューする価値があります。

于 2008-09-21T16:28:28.330 に答える
2

boost::program_optionsライブラリは、C++ を使用していて、Boost を使用する余裕がある場合に便利です。

于 2008-09-10T16:09:38.417 に答える
1

コマンドラインプロセッサライブラリを使用することをお勧めします。一部のロシア人はまともなものを作成しましたが、そこにはたくさんの人がいます。コマンドラインスイッチを解析するのではなく、アプリの目的に集中できるように、時間を節約できます。

于 2008-09-10T15:42:55.360 に答える
1

Getopt が唯一の方法です。

http://sourceforge.net/projects/csharpoptparse

于 2008-09-10T15:51:41.063 に答える
1

インタプリタパターンはどうですか? http://www.dofactory.com/net/interpreter-design-pattern

于 2016-07-28T16:12:48.183 に答える
0

このための言語については言及していませんが、getopt に関する本当に優れた Objective-C ラッパーを探している場合は、Dave Dribin の DDCLI フレームワークが非常に優れています。

http://www.dribin.org/dave/blog/archives/2008/04/29/ddcli

于 2008-09-10T15:47:21.307 に答える
0

Perl ではGetopts::stdGetopts::longを使用し、C ではGetopt関数も使用します。これにより、パラメーターの解析と形式が標準化されます。他の言語には、これらを処理するための異なるメカニズムがあります。

お役に立てれば

于 2008-09-10T15:47:22.260 に答える
0

標準設計は通常、getopt が行うことに従います。.NET、Python、C、Perl、PHP など、多くの言語用の getopt ライブラリがあります。

基本的な設計は、ループでチェックするために渡された引数を部分的に返すコマンドラインパーサーを持つことです。

この記事では、それについてもう少し詳しく説明します。

于 2008-09-10T15:47:32.243 に答える