Command Line Parser Libraryを使ってコマンドライン引数を解析する2

今回は前回に続いて、Command Line Parser Libraryを使ってコマンドライン引数を解析する方法について説明します。内容も前回の続きになりますので、前回(Command Line Parser Libraryを使ってコマンドライン引数を解析する1)を読んでいないと、何のことだかさっぱり分からないと思います。

大文字と小文字を区別する

今まで紹介してきた方法で解析すると、オプション名の大文字と小文字が区別されません。つまり、"o"というオプション名でも、"O"というオプション名でも同じものとして扱われます。

大文字と小文字が区別されるようにするには、CaseSensitiveプロパティをTrueにしたParserSettingsを使ってParserオブジェクトを作成し、このParseArgumentsメソッドを使って解析を行います。

以下にその例を示します。

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
Module Module1
    'エントリポイント
    Sub Main(args As String())
        'Optionsクラスのインスタンスを作成
        Dim opts = New Options()
 
        '大文字と小文字を区別するようにする
        Dim p = New CommandLine.Parser(Sub(w) w.CaseSensitive = True)
        'コマンドライン引数を解析する
        Dim isSuccess As Boolean = p.ParseArguments(args, opts)
        '解析結果を表示
        Console.WriteLine("OutputFile: {0}", opts.OutputFile)
        Console.WriteLine("Overwrite: {0}", opts.Overwrite)
 
        Console.ReadLine()
    End Sub
End Module
  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
//エントリポイント
static void Main(string[] args)
{
    //Optionsクラスのインスタンスを作成
    var opts = new Options();
 
    //大文字と小文字を区別するようにする
    var p = new CommandLine.Parser(with => with.CaseSensitive = true);
    //コマンドライン引数を解析する
    bool isSuccess = p.ParseArguments(args, opts);
    //解析結果を表示
    Console.WriteLine("OutputFile: {0}", opts.OutputFile);
    Console.WriteLine("Overwrite: {0}", opts.Overwrite);
 
    Console.ReadLine();
}

不明なオプションを無視する

デフォルトでは、コマンドライン引数に不明なオプション(Option属性で定義されていない、先頭にダッシュやハイフンが付いている文字列)が指定されていた時、ParseArgumentsメソッドがFalseを返します。不明なオプションが指定されていても無視するには、ParserSettings.IgnoreUnknownArgumentsをTrueにします。

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
Module Module1
    'エントリポイント
    Sub Main(args As String())
        'Optionsクラスのインスタンスを作成
        Dim opts = New Options()
 
        '不明なオプションを無視する
        Dim p = New CommandLine.Parser(Sub(w) w.IgnoreUnknownArguments = True)
        'コマンドライン引数を解析する
        Dim isSuccess As Boolean = p.ParseArguments(args, opts)
        '解析結果を表示
        Console.WriteLine("OutputFile: {0}", opts.OutputFile)
        Console.WriteLine("Overwrite: {0}", opts.Overwrite)
 
        Console.ReadLine()
    End Sub
End Module
  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
//エントリポイント
static void Main(string[] args)
{
    //Optionsクラスのインスタンスを作成
    var opts = new Options();
 
    //不明なオプションを無視する
    var p = new CommandLine.Parser(with => with.IgnoreUnknownArguments = true);
    //コマンドライン引数を解析する
    bool isSuccess = p.ParseArguments(args, opts);
    //解析結果を表示
    Console.WriteLine("OutputFile: {0}", opts.OutputFile);
    Console.WriteLine("Overwrite: {0}", opts.Overwrite);
 
    Console.ReadLine();
}

同時に指定できないオプションを設定する

私が試した限りでは、この機能はドキュメントで説明されているのとは全く違った(むしろ逆の)動作をしました。ドキュメントの記述と実際の動作のどちらが正しいのか分かりませんが、ここでは実際の動作に基づいて説明します。

あるオプションと別のオプションを同時に指定できないようにする(排他的にする)には、Option属性のMutuallyExclusiveSetプロパティを使います。MutuallyExclusiveSetプロパティの値が同じオプションは1つしか指定できなくなります。

補足

ドキュメントの「Mutually Exclusive Options」では、MutuallyExclusiveSetプロパティの値が違うオプションを組み合わせて使うと解析に失敗すると説明されています。

以下の例では、TextFileとXmlFileのMutuallyExclusiveSetが"file"ですので、これらのオプションを同時に指定できません。

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
Public Class Options
    <CommandLine.Option("t"c, "textfile", MutuallyExclusiveSet:="file")> _
    Public Property TextFile As String
 
    <CommandLine.Option("x"c, "xmlfile", MutuallyExclusiveSet:="file")> _
    Public Property XmlFile As String
 
    <CommandLine.Option("v"c)> _
    Public Property Overwrite As Boolean
End Class
  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
public class Options
{
    [CommandLine.Option('t', "textfile", MutuallyExclusiveSet = "file")]
    public string TextFile
    {
        get;
        set;
    }
 
    [CommandLine.Option('x', "xmlfile", MutuallyExclusiveSet = "file")]
    public string XmlFile
    {
        get;
        set;
    }
 
    [CommandLine.Option('v')]
    public bool Overwrite
    {
        get;
        set;
    }
}

このMutuallyExclusiveSetを有効にするには、解析を行うときに、MutuallyExclusiveプロパティがTrueのParserを使う必要があります。Parser.DefaultのMutuallyExclusiveはFalseだからです。

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
Module Module1
    'エントリポイント
    Sub Main(args As String())
        'Optionsクラスのインスタンスを作成
        Dim opts = New Options()
 
        'MutuallyExclusiveをTrueにする
        Dim p = New CommandLine.Parser(Sub(w) w.MutuallyExclusive = True)
        'コマンドライン引数を解析する
        Dim isSuccess As Boolean = p.ParseArguments(args, opts)
 
        Console.ReadLine()
    End Sub
End Module
  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
//エントリポイント
static void Main(string[] args)
{
    //Optionsクラスのインスタンスを作成
    var opts = new Options();
 
    //MutuallyExclusiveをTrueにする
    var p = new CommandLine.Parser(with => with.MutuallyExclusive = true);
    //コマンドライン引数を解析する
    bool isSuccess = p.ParseArguments(args, opts);
 
    Console.ReadLine();
}

このようにして以下のようなコマンドライン引数を渡すと、解析に失敗します。

-t 1.txt -x 1.xml

MutuallyExclusiveSetに何も指定されていないオプションであれば、同時に複数指定可能です。

カルチャを変更する

前回指摘したように、例えばコマンドライン引数から整数のオプション値を取得する時、文字列を整数に変換するという工程が入りますので、カルチャの影響を受ける可能性があります。

解析で使用するカルチャを変更するには、ParserのParsingCultureプロパティを変更します。

なおParser.DefaultのParsingCultureプロパティは、InvariantCultureです。

以下の例では、解析に使用するカルチャを"ja-JP"に変更しています。

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
Module Module1
    'エントリポイント
    Sub Main(args As String())
        'Optionsクラスのインスタンスを作成
        Dim opts = New Options()
 
        'カルチャを"ja-JP"に変更する
        Dim p = New CommandLine.Parser(Sub(w) w.ParsingCulture =
            New System.Globalization.CultureInfo("ja-JP"))
        'コマンドライン引数を解析する
        Dim isSuccess As Boolean = p.ParseArguments(args, opts)
 
        Console.ReadLine()
    End Sub
End Module
  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
//エントリポイント
static void Main(string[] args)
{
    //Optionsクラスのインスタンスを作成
    var opts = new Options();
 
    //カルチャを"ja-JP"に変更する
    var p = new CommandLine.Parser(with => with.ParsingCulture =
        new System.Globalization.CultureInfo("ja-JP"));
    //コマンドライン引数を解析する
    bool isSuccess = p.ParseArguments(args, opts);
 
    Console.ReadLine();
}

「Parser.Default」と「new Parser()」の違い

非常に厄介なことに、前回使用していた「Parser.Default」と、上記で使用している新しく作成したParserオブジェクトは、デフォルトのプロパティ値が異なりますので、これらを使って解析した結果も異なる可能性があります。

Parser.DefaultのCaseSensitiveはFalseですが、コンストラクタの引数に何も指定せずに作成したParserオブジェクトのCaseSensitiveはTrueです。ParsingCultureは、前者がInvariantCultureで、後者がThread.CurrentThread.CurrentCultureです。

MutuallyExclusiveとIgnoreUnknownArgumentsは、両者ともFalseです。

また、次回詳しく説明しますが、HelpWriterプロパティも両者で異なり、Parser.DefaultはConsole.Errorですが、新しく作成したParserオブジェクトはnullです。この違いも非常に大きいです。

次回予告

今回で終わりにする予定でしたが、予想外に長くなってしまいましたので、ヘルプを表示する機能の説明は次回させていただきます。

コメント



ページ情報
[ トップ ]   [ 編集 | 凍結 | 差分 | バックアップ | 添付 | 複製 | 名前変更 | リロード ]   [ 新規 | 子ページ作成 | 一覧 | 単語検索 | 最終更新 | ヘルプ ]