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

スポンサーリンク

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

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

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

サンプルコード

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

C# 全般
using System;

/// -----------------------------------------------------------------------------
/// <summary>
///     検証・エラーチェックをサポートした静的クラスです。
/// </summary>
/// -----------------------------------------------------------------------------

public sealed class Validation {

  #region Val メソッド (+2)

    /// -----------------------------------------------------------------------------
    /// <summary>
    ///     指定した文字列に含まれる数値を変換して返します。</summary>
    /// <param name="stTarget">
    ///     任意の有効な文字列。</param>
    /// <returns>
    ///     指定した文字列に含まれる数値。</returns>
    /// -----------------------------------------------------------------------------
    public static double Val(string stTarget) {
        // Null 値の場合は 0 を返す
        if (stTarget == null) {
            return 0D;
        }

        int iCurrent = 0;
        int iLength  = stTarget.Length;

        // 評価対象外の文字をスキップする
        for (iCurrent = 0; iCurrent < iLength; iCurrent++) {
            char chOne = stTarget[iCurrent];

            if ((chOne != ' ') && (chOne != ' ') && (chOne != '\t') && (chOne != '\n') && (chOne != '\r')) {
                break;
            }
        }

        // 終端までに有効な文字が見つからなかった場合は 0 を返す
        if (iCurrent >= iLength) {
            return 0D;
        }

        bool bMinus = false;

        // 先頭にある符号を判定する
        switch (stTarget[iCurrent]) {
            case '-':
                bMinus = true;
                iCurrent++;
                break;
            case '+':
                iCurrent++;
                break;
        }

        int ValidLength = 0;
        int Priod = 0;
        double dReturn = 0D;
        bool bDecimal   = false;
        bool bShisuMark = false;

        // 1 文字ずつ有効な文字かどうか判定する
        while (iCurrent < iLength) {
            char chCurrent = stTarget[iCurrent];

            if ((chCurrent == ' ') || (chCurrent == ' ') || (chCurrent == '\t') || (chCurrent == '\n') || (chCurrent == '\r')) {
                iCurrent++;
            } else if (chCurrent == '0') {
                iCurrent++;

                if ((iValidLength != 0) || bDecimal) {
                    iValidLength++;
                    dReturn = (dReturn * 10) + double.Parse(chCurrent.ToString());
                }
            } else if ((chCurrent >= '1') && (chCurrent <= '9')) {
                iCurrent++;
                iValidLength++;
                dReturn = (dReturn * 10) + double.Parse(chCurrent.ToString());
            } else if (chCurrent == '.') {
                iCurrent++;

                if (bDecimal) {
                    break;
                }

                bDecimal = true;
                iPriod = iValidLength;
            } else if ((chCurrent == 'e') || (chCurrent == 'E') || (chCurrent == 'd') || (chCurrent == 'D')) {
                bShisuMark = true;
                iCurrent++;
                break;
            } else {
                break;
            }
        }

        int iDecimal = 0;

        // 小数点が判定された場合
        if (bDecimal) {
            iDecimal = iValidLength - iPriod;
        }

        // 指数が判定された場合
        if (bShisuMark) {
            bool bShisuValid = false;
            bool bShisuMinus = false;
            double dCoef = 0D;

            // 指数を検証する
            while (iCurrent < iLength) {
                char chCurrent = stTarget[iCurrent];

                if ((chCurrent == ' ')  || (chCurrent == ' ') || (chCurrent == '\t') || (chCurrent == '\n') || (chCurrent == '\r')) {
                    iCurrent++;
                } else if ((chCurrent >= '0') && (chCurrent <= '9')) {
                    dCoef = (dCoef * 10) + double.Parse(chCurrent.ToString());
                    iCurrent++;
                } else if (chCurrent == '+') {
                    if (bShisuValid) {
                        break;
                    }

                    ShisuValid = true;
                    iCurrent++;
                } else if ((chCurrent != '-') || bShisuValid) {
                    break;
                } else {
                    bShisuValid = true;
                    bShisuMinus = true;
                    iCurrent++;
                }
            }

            // 指数の符号に応じて累乗する
            if (bShisuMinus) {
                dCoef += iDecimal;
                dReturn *= System.Math.Pow(10, - dCoef);
            } else {
                dCoef -= iDecimal;
                dReturn *= System.Math.Pow(10, dCoef);
            }
        } else if (bDecimal && (iDecimal != 0)) {
            dReturn /= System.Math.Pow(10, iDecimal);
        }

        // 無限大の場合は 0 を返す
        if (double.IsInfinity(dReturn)) {
            return 0D;
        }

        // マイナス判定の場合はマイナスで返す
        if (bMinus) {
            return -dReturn;
        }

        return dReturn;
    }

    /// -----------------------------------------------------------------------------
    /// <summary>
    ///     指定した文字に含まれる数値を変換して返します。</summary>
    /// <param name="chTarget">
    ///     任意の有効な文字。</param>
    /// <returns>
    ///     指定した文字に含まれる数値。</returns>
    /// -----------------------------------------------------------------------------
    public static int Val(char chTarget) {
        return (int)Val(chTarget.ToString());
    }

    /// -----------------------------------------------------------------------------
    /// <summary>
    ///     指定したオブジェクトに含まれる数値を変換して返します。</summary>
    /// <param name="oTarget">
    ///     任意の有効なオブジェクト。</param>
    /// <returns>
    ///     指定したオブジェクトに含まれる数値。</returns>
    /// -----------------------------------------------------------------------------
    public static double Val(object oTarget) {
        if (oTarget != null) {
            return Val(oTarget.ToString());
        }

        return 0D;
    }

  #endregion

}

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

C# 全般
    // 不正な文字を含む文字列から数値部分のみを取得する
    double dValue = Validation.Val("  -10 24 [不正な文字] 512  ");

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

関連するリファレンス

準備中です。

スポンサーリンク