Help us understand the problem. What is going on with this article?

【C#】コマンドラインオプションを解析してくれるクラスを作った

More than 3 years have passed since last update.

コマンドラインオプション

application.exe config/app.conf -u username -p password -x -y
みたいな感じでコマンドラインから起動した時に、どんな引数が渡されてるのかってのをある程度楽に解析したい。

…って時ありません?

やりましょう

とりあえず結論…というかコードから見ていただきましょう。

ArgumentMap.cs
public class ArgumentMap
{
    private List<string> mainArgs = new List<string>();
    private Dictionary<string, string> optionMap = new Dictionary<string, string>();
    private List<string> optionSwitches = new List<string>();

    public void Init(string[] args)
    {
        int i = 0;
        while (i < args.Length)
        {
            string arg = args[i];
            if (arg.StartsWith("-"))
            {
                if (i + 1 < args.Length)
                {
                    if (args[i + 1].StartsWith("-"))
                    {
                        this.optionSwitches.Add(args[i]);
                    }
                    else
                    {
                        this.optionMap[arg] = args[i + 1];
                        i++;
                    }
                }
            }
            else
            {
                this.mainArgs.Add(arg);
            }

            i++;
        }
    }

    public List<string> GetMainArgs()
    {
        return this.mainArgs;
    }

    public bool HasSwitch(string key)
    {
        return this.optionSwitches.Contains(key);
    }

    public string GetOption(string key, string defaultValue = null)
    {
        if (this.optionMap.ContainsKey(key))
        {
            return this.optionMap[key];
        }

        return defaultValue;
    }

    public int GetOptionInt(string key, int defaultValue)
    {
        if (this.optionMap.ContainsKey(key))
        {
            string value = this.optionMap[key];
            int intValue = defaultValue;
            if (int.TryParse(value, out intValue))
            {
                return intValue;
            }
        }

        return defaultValue;
    }

    public bool GetOptionBool(string key, bool defaultValue)
    {
        if (this.optionMap.ContainsKey(key))
        {
            string value = this.optionMap[key];
            bool boolValue = defaultValue;
            if (bool.TryParse(value, out boolValue))
            {
                return boolValue;
            }
        }

        return defaultValue;
    }
}

コメントは各自入れて使ってください。書くのが面倒だった。
メソッド名でだいたいわかるだろうから良いかなって。

使い方

冒頭で書いたのと同じように起動されたとして、
application.exe config/app.conf -u username -p password -x -y

まずはインスタンスを生成。

static void main(string[] args)
{
    ArgumentMap amap = new ArgumentMap();
    amap.Init(args);
      .
      .
      .
}

config/app.conf はオプションスイッチ無しの引数、必ず指定してね!みたいな引数として使いたい場合に。
ここを取り出すには、

List<string> mainArgs = amap.GetMainArgs();
foreach (string mainArg in mainArgs)
{
    Console.WriteLine("mainArg: {0}", mainArg);
    // mainArg: config/app.conf
}

みたいな。
複数あっても対応はしてるし入力された順番に格納されてるけど、そこ複数にするなら素直に次の例みたいな指定をさせたほうが良いような気もする。

-u username -p passwordは、オプションスイッチ有りの引数。
-u に対応している値が username-pに対応している値がpasswordといった感じの。
コレを取り出すには、

string userName = amap.GetOption("-u", string.Empty);
Console.WriteLine("userName: {0}", userName);
// userName: username

string pass = amap.GetOption("-p", string.Empty);
Console.WriteLine("pass: {0}", pass);
// pass: password

みたいな。
第二引数に指定してるのは、オプションスイッチが無かった場合に返ってきてほしい値。
ここではstring.Emptyを指定している。
ここで指定をしなかった場合はnullが返ってくるので、受け取った側でnullチェックをすればエラー処理とかもできると思われ。
たとえば、

string permission = amap.GetOption("-a", "user");
Console.WriteLine("permission: {0}", permission);
// permission: user

string lang = amap.GetOption("-l");
if (lang == null)
{
    Console.WriteLine("Argument error. Please specify '-l' option.");
}

みたいな。
ちなみに数値や真偽値として値を受け取りたい場合は、それぞれGetOptionInt(string key, int defaultValue)GetOptionBool(string key, bool defaultValue)で実現できる。
こちらでdefaultValueを特に指定していないのは、流石に数値とかは既定値にしたいものに個人差があるかなあということで。

-x -yは、オプションスイッチ単体で意味を成すもの。
-xが指定されているときのみこの機能が有効、とか。

if (amap.HasSwitch("-x"))
{
    Console.WriteLine("Enabled x.");
}
if (amap.HasSwitch("-y"))
{
    Console.WriteLine("Enabled y.");
}
if (amap.HasSwitch("-z"))
{
    Console.WriteLine("Enabled z.");
}
// Enabled x.
// Enabled y.

truefalseで結果が返ってくるので、if文で判定して煮るなり焼くなり。

最後に

自分でテストしたりはまだ殆どしてないので、不具合とか結構あるかもしれないです。
あんまり期待せずに使ってください。

宣伝的な

今回紹介したものも含めたライブラリをgithubで公開してるので、よかったら見てやってください。
ここマズイよ―、とかありましたらpull requestなりtwitterでのご報告なりをお願いします。
他のリポジトリはあんまり見ないでいただけると嬉しいです。とりあえず投げとくか、って感じで作ってるので…。

github: https://github.com/mik-claire/MikLib
twitter: https://twitter.com/mik_claire

mik_claire
ド素人なC#er。DBややこしくて死にかけてるひと。 teratailと同時に質問として記事を投稿したりしてます。
Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away