読者です 読者をやめる 読者になる 読者になる

前に作ったStringListのVB.NET版、今回、CSV変換にあたってクオート処理が必要になったのでとりあえず実装‥‥、したのですが、作成するCSVファイルの種類によってクオート処理を切り替える必要が出てきたので、CSV変換で使うクオート処理を差し替えられる様に変更。

Public Class StringList
    Private FQuoteGetter As IQuoteTextGetter = getGefaultQuote()

()

    ''' <summary>
    ''' CommaTextQuoteでクオート処理するための外部処理を指定
    ''' </summary>
    ''' <param name="aQuoteGetter">クオート処理を行うオブジェクト</param>
    ''' <remarks></remarks>
    Public Sub setCommaQuote(ByVal aQuoteGetter As IQuoteTextGetter)
        If aQuoteGetter Is Nothing Then
            aQuoteGetter = getGefaultQuote()
        End If

        FQuoteGetter = aQuoteGetter
    End Sub

    ''' <summary>
    ''' デフォルトで使うクオート処理
    ''' </summary>
    ''' <returns>デフォルトのクオート処理オブジェクト</returns>
    ''' <remarks></remarks>
    Private Function getGefaultQuote() As IQuoteTextGetter
        Return New QuoteTextDefault
    End Function

()

    ''' <summary>
    ''' setCommaQuoteで指定したインターフェイスを使ってクオート処理したCSVを取得
    ''' </summary>
    ''' <returns>文字列リストをクオート処理して連結したCSVの行</returns>
    ''' <remarks></remarks>
    Public ReadOnly Property CommaTextQuote As String
        Get
            Dim tmpList As New List(Of String)
            For Each tmpRow As String In ObjectList
                tmpList.Add(FQuoteGetter.getQuoteText(tmpRow))
            Next
            Return JoinText(tmpList, ",")
        End Get
    End Property
    
    ''' <summary>
    ''' 指定したリストをaSeparatorを区切りにして連結する
    ''' </summary>
    ''' <param name="aSourceList"></param>
    ''' <param name="aSeparator"></param>
    ''' <returns></returns>
    ''' <remarks></remarks>
    Protected Function JoinText(ByVal aSourceList As List(Of String), _
                                Optional ByVal aSeparator As String = vbCrLf) As String
        Dim sBuff As String
        sBuff = ""
        For i As Integer = 0 To aSourceList.Count - 1
            sBuff = sBuff + aSourceList(i) + aSeparator
        Next
        Return sBuff.Substring(0, sBuff.Length - aSeparator.Length)
    End Function

()

    ''' <summary>
    ''' 標準のクオート処理
    ''' </summary>
    ''' <remarks></remarks>
    Private Class QuoteTextDefault
        Implements IQuoteTextGetter

        Public Function getQuoteText(Source As String) As String Implements IQuoteTextGetter.getQuoteText
            Dim ResultText As String = Source
            ' "があった場合は"でエスケープ
            ResultText = ResultText.Replace("""", """""")

            Select Case True
                Case ResultText = ""
                    ' 空文字はクオートしない
                Case IsNumeric(ResultText)
                    ' 数値化出来る場合で、カンマ入り、前ゼロ等の特殊な書式だった場合は""でくくる
                    ' そうでない、綺麗な数値書式の場合はくくらない
                    Dim tmpNumeric As Decimal = CDec(ResultText)
                    If tmpNumeric.ToString <> ResultText Then
                        ResultText = doQuote(ResultText)
                    End If
                Case Else
                    ' それ以外ならくくる
                    ResultText = doQuote(ResultText)
            End Select
            Return ResultText
        End Function

        ''' <summary>
        ''' クオート処理
        ''' </summary>
        ''' <param name="aSource"></param>
        ''' <returns></returns>
        ''' <remarks></remarks>
        Private Function doQuote(ByVal aSource As String) As String
            Return """" + aSource + """"
        End Function
    End Class

クオート処理用のインターフェイス

''' <summary>
''' 文字列をクオート処理された文字列に変換するインターフェイス
''' </summary>
''' <remarks></remarks>
Public Interface IQuoteTextGetter
    ''' <summary>
    ''' クオート処理したテキストを取得
    ''' </summary>
    ''' <param name="Source">元のテキスト</param>
    ''' <returns>クオート済みテキスト</returns>
    ''' <remarks></remarks>
    Function getQuoteText(ByVal Source As String) As String
End Interface


''' <summary>
''' クオートしないQuoteText
''' </summary>
''' <remarks></remarks>
Public Class QuoteTextNoQuote
    Implements IQuoteTextGetter

    ''' <summary>
    ''' クオート処理したテキストを取得
    ''' </summary>
    ''' <param name="Source">元のテキスト</param>
    ''' <returns>クオート済みテキスト</returns>
    ''' <remarks></remarks>
    Public Function getQuoteText(Source As String) As String Implements IQuoteTextGetter.getQuoteText
        Return Source
    End Function
End Class

''' <summary>
''' 無条件にクオートするQuoteText
''' </summary>
''' <remarks></remarks>
Public Class QuoteTextAllQuote
    Implements IQuoteTextGetter

    ''' <summary>
    ''' クオート処理したテキストを取得
    ''' </summary>
    ''' <param name="Source">元のテキスト</param>
    ''' <returns>クオート済みテキスト</returns>
    ''' <remarks></remarks>
    Public Function getQuoteText(Source As String) As String Implements IQuoteTextGetter.getQuoteText
        Return """" + Source + """"
    End Function
End Class


使用例。

Public Function getMemberList(Optional ByVal aQuote As IQuoteTextGetter = Nothing) As String
    Dim textLine As New StringList
    textLine.setCommaQuote(aQuote)

    textLine.Add("京子")
    textLine.Add("0328")
    textLine.Add("156")

    textLine.Add("結衣")
    textLine.Add("0422")
    textLine.Add("160")

    ' 空文字のテスト
    textLine.Add("")
    textLine.Add("0724")
    textLine.Add("153")

    textLine.Add("ちなちゅ")
    textLine.Add("1106")
    textLine.Add("149")

    Return textLine.CommaTextQuote
End Function


' ---------------- 実行結果 ----------------

getMemberList()"京子","0328",156,"結衣","0422",160,,"0724",153,"ちなちゅ",1106,149

getMemberList(New QuoteTextAllQuote)"京子","0328","156","結衣","0422","160","","0724","153","ちなちゅ","1106","149"

getMemberList(New QuoteTextNoQuote)
    → 京子,0328,156,結衣,0422,160,,0724,153,ちなちゅ,1106,149