kkamegawa's weblog

Visual Studio,TFS,ALM,VSTS,DevOps関係のことについていろいろと書いていきます。Google Analyticsで解析を行っています

コマンドライン解析

お仕事の正式なものじゃないけれど、いい機会だし、少しだけ汎用的な、使い廻せそうなものを考えてみました。今回はこれくらいで要件を満たせるんだけれど、

  • もっとコマンドラインが増えた場合の対応(UNIX系みたいにコマンドラインの限界に挑戦する(笑)ような数の引数)
  • 任意の順番をサポートする(今回は子プロセス用なので、順番もきめうちできる)
  • もう少し抽象化したクラスを用意する
  • Exceptionクラスそのまま投げちゃまずいだろう
  • 大文字小文字考慮してません

あたりが改良点かな。ま、それは次のものを作ったとき(^^;。コマンドライン引数、どんな解析処理していますか*1?コマンドライン解析といえば、確かGNUのライブラリにもあった気がする。

    using System.Collections;

    class ArgumentValues
    {
        public string Name;
        public int    Type; //(0:任意, 1:文字, 2:整数のみ)
        public string Value;
    }

    public class Arguments
    {
        ArrayList m_oArgumentList;

        /// <summary>
        /// 取るべき引数リストと、その中に含まれなくてはならないデータ型を指定します。
        /// </summary>
        /// <param name="p_args">引数の名前リスト</param>
        /// <param name="p_iType">型リスト(0:任意, 1:整数のみ)</param>
        public Arguments(string[] p_args, int[] p_iType){
            if(p_args.Length != p_iType.Length) {
                Exception exp = new Exception("型と解析パラメータが一致しない");
                throw exp;
            }
            m_oArgumentList = new ArrayList(p_args.Length);
            
            int i = 0;
            foreach(string arg in p_args){
                ArgumentValues oValues = new ArgumentValues();
                oValues.Name = arg;
                oValues.Type = p_iType[i++];
                oValues.Value = null;
                m_oArgumentList.Add(oValues);
            }
        }

        /// <summary>
        /// Main()に渡された引数群をパースして、指定されたデータ型と不一致があれば例外を発生させる。
        /// </summary>
        /// <param name="p_ArgumentStrings">Main()に渡された引数文字列</param>
        public void Parse(string[] p_ArgumentStrings) {
            if(p_ArgumentStrings.Length != m_oArgumentList.Count) {
                Exception exp = new Exception("引数の数が不足、あるいは多すぎます");
                throw exp;
            }
            int i = 0;
            foreach(string strParam in p_ArgumentStrings) {
                ArgumentValues oVal = (ArgumentValues)m_oArgumentList[i];
                switch(oVal.Type) {
                    case 1:
                        for(int j = 0;j < strParam.Length;j++) {
                            if(Char.IsDigit(strParam, j) == false) {
                                Exception exp = new Exception(String.Format("{0}番目の引数が整数ではありません", i));
                                throw exp;
                            }
                        }
                        break;
                    default:
                        break;
                }
                oVal.Value = strParam;
                i++;
            }
        }

        /// <summary>
        /// 指定したタイプの引数に関連付けられた値を返却します。
        /// </summary>
        /// <param name="p_strArgumentName">引数の名前</param>
        /// <returns>値</returns>
        public string Lookup(string p_strArgumentName) {
            string strReturn = null;

            foreach(ArgumentValues oVal in m_oArgumentList) {
                if(p_strArgumentName.CompareTo(oVal.Name) == 0) {
                    strReturn = oVal.Value;
                }
            }
            return strReturn;
        }
    }

    void Main(string[] args)
    {
        string[] strType = {"hoge","foo","bar",};
        int[] iType = {0,0,1};
        try
        {
            Arguments oArg = new Arguments(strType, iType);
            oArg.Parse(args);
        }
        catch(Exception exp)
        {
           Console.WriteLine(exp.toString());
        }
    }

こうした方がいいよーってなつっこみも歓迎(^^;。ただし、.NET Framework 1.1でも動くソースで。

*1:それとも最近はコマンドライン引数解析する必要のある人少ないのかな