VB2008でコマンドライン スイッチの判定を実装してみた

http://devadjust.exblog.jp/20069155/
この記事を見て、久々に何か書いてみたいな!と思ったので、書いてみます。

まず、コマンドライン引数のパーサを書くんだけど、パースした結果をどう扱えるか? どれだけ扱いやすいか? という事から考えてみた。私なら、こう書きたい。

        Dim opts = (New OptionParser).Parse(args)   'この辺はきっとごにょごにょする

        Dim hogeParam1 As String = "hogedefault1"   'set default
        Dim hogeParam2 As String = "hogedefault2"   'set default
        If opts.ContainsKey("hoge") Then            'こんな感じで「このパラメータあれば」って書けるとうれしい
            With opts("hoge")                       'VB風味を加える
                If .Count >= 1 Then                 '個別の引数はこんな感じで
                    hogeParam1 = .Item(0)
                End If
                If .Count >= 2 Then
                    hogeParam2 = .Item(1)
                End If
            End With
        End If

こんな感じでスイッチの部分はディクショナリのキーになってて、そのスイッチの引数はディクショナリの値(コレクション)に要素として入ってる。きっと書くときこうなってると嬉しい感じがする。で、これをやってくれるOptionParserを書いた。

Public Class OptionParser
    Private listOfOptionName As New List(Of String)
    Private swChar As Char
    Public Sub New(ByVal args() As String, ByVal swc As Char)
        swChar = swc
        listOfOptionName = args.Distinct().ToList()
    End Sub
    Public Function Parse(ByVal args() As String) As Dictionary(Of String, List(Of String))
        Parse = New Dictionary(Of String, List(Of String))
        For i = 0 To args.Length - 1
            Dim targetArg = args(i)
            If listOfOptionName.Exists(Function(n) String.Format("{0}{1}", swChar, n) = targetArg) Then
                Parse.Add(targetArg.Substring(1, targetArg.Length - 1), New List(Of String))
            Else
                If Parse.Count > 0 AndAlso targetArg(0) <> swChar Then
                    Parse.Last.Value.Add(targetArg)
                Else
                    Debug.Print("{0} droped.index={1}", targetArg, i)
                End If
            End If
        Next
    End Function
End Class

呼ぶときはこんな感じに。

    Sub Main(ByVal args() As String)
        Dim myOptions() As String = {"hoge", "fuga", "piyo"}
        Dim opts = (New OptionParser(myOptions, "-"c)).Parse(args)

コンストラクタの第二引数に"-"cとか書いてあるのは、ほら、あれですよ、スイッチって"/"のコマンドとかもあるじゃないですか。そこらへんのフィーリングに引数ひとつで対応する為。考えすぎかもしれないけど。

呼び出し部分全体を、もっかい貼り付けてみよう。

Module OptionParseSample
    Sub Main(ByVal args() As String)
        Dim myOptions() As String = {"hoge", "hoge", "fuga", "piyo"}
        Dim opts = (New OptionParser(myOptions, "-"c)).Parse(args)

        'パースした結果を出力
        For Each item In opts
            Console.WriteLine(item.Key)
            For Each p In item.Value
                Console.WriteLine("  {0}", p)
            Next
        Next

        'こんな風に書けるよ!
        Dim hogeParam1 As String = "hogedefault1"   'set default
        Dim hogeParam2 As String = "hogedefault2"   'set default
        If opts.ContainsKey("hoge") Then
            With opts("hoge")
                If .Count >= 1 Then
                    hogeParam1 = .Item(0)
                End If
                If .Count >= 2 Then
                    hogeParam2 = .Item(1)
                End If
            End With
        End If
    End Sub
End Module

お楽しみでほいほいーっと書いたので、テキトーにバグってるかもしんない(予防線)。でもまあ、OKだ。初めてGitHubリポジトリも作ってアップしちゃったー! きゃー!w

でも、このリポジトリへのリンクとかどうやって貼るんだろ? ま、それはあとで勉強しよう。ひとまず送信!