VB.NET指定した文字列に含まれる値を取得する (Val)

スポンサーリンク

ある文字列を数値に変換する場合は、不正な文字が入っている場合を考慮する必要があります。殆どのキャストでは、不正な文字が入っていると失敗します。(例外が発生する)

VB6 には Val という関数がありました。これは、数値として読み取り可能な部分のみを返すことができます。不正な文字ばかりの場合は、0 を返すことができるので、例外を考慮しなくて良いわけです。

VB.NET では Microsoft.VisualBasic 名前空間配下にある Val メソッドがこれにあたります。これまた、Microsoft.VisualBasic 名前空間配下を使いたくないという方のために自作してみました。指数の考慮があるため、ベタに組むほかありませんでした。8 進数、16 進数の対応は省きました。(言語によって表記方法が違うため)エラー検証でもあまり使う機会は少なくなりましたが、とりあえず紹介しておきます。

サンプルコード

以下にサンプルコードを示します。

VB.NET 全般
Option Strict On

Public NotInheritable Class Validation

  #Region " Val メソッド (+2) "

    ''' -----------------------------------------------------------------------------
    ''' <summary>
    '''     指定した文字列に含まれる数値を変換して返します。</summary>
    ''' <param name="stTarget">
    '''     任意の有効な文字列。</param>
    ''' <returns>
    '''     指定した文字列に含まれる数値。<returns>
    ''' -----------------------------------------------------------------------------
    Public Shared Overloads Function Val(ByVal stTarget As String) As Double
        ' Null 値の場合は 0 を返す
        If stTarget Is Nothing Then
            Return 0#
        End If

        Dim iCurrent As Integer
        Dim iLength  As Integer = stTarget.Length

        ' 評価対象外の文字をスキップする
        For iCurrent = 0 To iLength
            Select Case stTarget.Chars(iCurrent)
                Case " "c, " "c, ControlChars.Tab, ControlChars.Cr, ControlChars.Lf
                Case Else
                    Exit For
            End Select
        Next iCurrent

        ' 終端までに有効な文字が見つからなかった場合は 0 を返す
        If iCurrent >= iLength Then
            Return 0#
        End If

        Dim bMinus As Boolean

        ' 先頭にある符号を判定する
        Select Case stTarget.Chars(iCurrent)
            Case "-"c
                bMinus = True
                iCurrent += 1
            Case "+"c
                iCurrent += 1
        End Select

        Dim iValidLength As Integer
        Dim iPriod       As Integer
        Dim dReturn      As Double
        Dim bDecimal     As Boolean
        Dim bShisuMark   As Boolean

        ' 1 文字ずつ有効な文字かどうか判定する
        While (iCurrent < iLength)
            Dim chCurrent As Char = stTarget.Chars(iCurrent)

            Select Case chCurrent
                Case " "c, " "c, ControlChars.Tab, ControlChars.Cr, ControlChars.Lf
                    iCurrent += 1
                Case "0"c
                    iCurrent += 1

                    If iValidLength <> 0 OrElse bDecimal Then
                        iValidLength += 1
                        dReturn = (dReturn * 10) + Double.Parse(chCurrent.ToString())
                    End If
                Case "1"c To "9"c
                    iCurrent += 1
                    iValidLength += 1
                    dReturn = (dReturn * 10) + Double.Parse(chCurrent.ToString())
                Case "."c
                    iCurrent += 1

                    If bDecimal Then
                        Exit While
                    End If

                    bDecimal = True
                    iPriod = iValidLength
                Case "e"c, "E"c, "d"c, "D"c
                    bShisuMark = True
                    iCurrent += 1
                    Exit While
                Case Else
                    Exit While
            End Select
        End While

        Dim iDecimal As Integer

        ' 小数点が判定された場合
        If bDecimal Then
            iDecimal = iValidLength - iPriod
        End If

        ' 指数が判定された場合
        If bShisuMark Then
            Dim bShisuValid As Boolean
            Dim bShisuMinus As Boolean
            Dim dCoef       As Double

            ' 指数を検証する
            While (iCurrent < iLength)
                Dim chCurrent As Char = stTarget.Chars(iCurrent)

                If (chCurrent = " "c) OrElse (chCurrent = " "c) OrElse (chCurrent = ControlChars.Tab) OrElse (chCurrent = ControlChars.Cr) OrElse (chCurrent = ControlChars.Lf) Then
                    iCurrent += 1
                ElseIf (chCurrent >= "0"c) AndAlso (chCurrent <= "9"c) Then
                    dCoef = (dCoef * 10) + Double.Parse(chCurrent.ToString())
                    iCurrent += 1
                ElseIf chCurrent = "+"c Then
                    If bShisuValid Then
                        Exit While
                    End If

                    bShisuValid = True
                    iCurrent += 1
                ElseIf (chCurrent <> "-"c) OrElse (bShisuValid) Then
                    Exit While
                Else
                    bShisuValid = True
                    bShisuMinus = True
                    iCurrent += 1
                End If
            End While

            ' 指数の符号に応じて累乗する
            If bShisuMinus Then
                dCoef += iDecimal
                dReturn *= System.Math.Pow(10, - dCoef)
            Else
                dCoef -= iDecimal
                dReturn *= System.Math.Pow(10, dCoef)
            End If
        ElseIf (bDecimal) AndAlso (iDecimal <> 0) Then
            dReturn /= System.Math.Pow(10, iDecimal)
        End If

        ' 無限大の場合は 0 を返す
        If Double.IsInfinity(dReturn) Then
            Return 0#
        End If

        ' マイナス判定の場合はマイナスで返す
        If bMinus Then
            Return -dReturn
        End If

        Return dReturn
    End Function

    ''' -----------------------------------------------------------------------------
    ''' <summary>
    '''     指定した文字に含まれる数値を変換して返します。</summary>
    ''' <param name="chTarget">
    '''     任意の有効な文字。</param>
    ''' <returns>
    '''     指定した文字に含まれる数値。<returns>
    ''' -----------------------------------------------------------------------------
    Public Shared Overloads Function Val(ByVal chTarget As Char) As Integer
        Return CType(Val(chTarget.ToString()), Integer)
    End Function

    ''' -----------------------------------------------------------------------------
    ''' <summary>
    '''     指定したオブジェクトに含まれる数値を変換して返します。</summary>
    ''' <param name="oTarget">
    '''     任意の有効なオブジェクト。</param>
    ''' <returns>
    '''     指定したオブジェクトに含まれる数値。<returns>
    ''' -----------------------------------------------------------------------------
    Public Shared Overloads Function Val(ByVal oTarget As Object) As Double
        If Not oTarget Is Nothing Then
            Return Val(oTarget.ToString())
        End If

        Return 0#
    End Function

  #End Region

End Class

使用例は以下のようになります。

VB.NET 全般
    ' 不正な文字を含む文字列から数値部分のみを取得する
    Dim dValue As Double = Validation.Val("  -10 24 [不正な文字] 512  ");

    MessageBox.Show(dValue.ToString()); '-1024

関連するリファレンス

準備中です。

スポンサーリンク