【VBA】文字列⇔数値の型変換で計算エラーを防ぐ方法(コピペOK)

VBA
スポンサーリンク
スポンサーリンク

この記事でできること

  • VBAで文字列と数値を正しく変換できる(CStr / CLng / CDbl / Val)
  • 文字列結合と数値加算の違い(”1″+”2″=”12″ 問題)を理解できる
  • CSVから取り込んだ文字列型数値を一括で正しい数値に変換できる

対象: Excel 2016以降 / Microsoft 365、Windows 10/11


完成イメージ(Before / After)

Before(手作業):

  1. CSVファイルを取り込んだら数値が文字列になっている
  2. SUM関数で合計しても0になる
  3. セルの左上に緑の三角マーク(文字列型数値の警告)
  4. VBAで足し算したら文字列結合になった

After(マクロ実行):

  1. 対象列を指定してマクロを実行する
  2. 文字列型数値が正しい数値に一括変換される
  3. 全角数字やカンマ区切りも自動で対応
  4. 1000件が数秒で完了。SUM関数も正しく動く

データシート(処理前):

A B C
1 商品名 数量 金額
2 商品A ‘100 ‘1,980
3 商品B ‘200 ‘2,550
4 商品C ‘350 ‘3,333

※ 先頭のアポストロフィ(’)は表示されないが、文字列型として格納されている

データシート(処理後):

A B C
1 商品名 数量 金額
2 商品A 100 1980
3 商品B 200 2550
4 商品C 350 3333

CSVファイルを取り込んだあとにSUM関数で合計を出したら0になった。セルを見ると数字が入っているのに、左上に緑の三角マークが出ている。数値に見えるのに実は文字列だった。

さらにVBAで足し算しようとしたら、String型の変数に入った "100""200"+ で足した結果が "100200" になった。数値の足し算ではなく、文字列の結合になっていた。原因は、CSVから取り込んだデータが「見た目は数値だが型は文字列」だったこと。

CDbl で一括変換するマクロを作ってからは、CSV取り込み→型変換→集計まで全自動。毎月のデータ集計で数字が合わないと悩む時間がゼロになった。

VBAの型変換はExcelの暗黙変換に慣れていると絶対にハマる。文字列の “100” と数値の 100 は別物。同じ表示なのに計算できないのは、知らないと原因がわからない。エラー処理で止まらないマクロを作る方法と組み合わせれば、型変換エラーも安全にハンドリングできる。

文字列の “100” と数値の 100 は、見た目は同じでも VBA にとっては別物。


事前準備

シート構成を用意する

実務版コードでは以下の構成を使う。最小版はシート構成不要(イミディエイトウィンドウで結果を確認する)。

データシート — 型変換の対象データ

内容
A列 商品名 商品A
B列 数量(文字列型数値) ‘100
C列 金額(文字列型数値) ‘1,980
  • 1行目はヘッダー。データは2行目から入力する
  • 変換対象の列番号をコード内で指定する

バックアップを取る

セルの値を上書きする処理のため、実行前にファイルのコピーを取っておくこと。テスト用のダミーデータで動作確認してから本番データで実行することを強く推奨する。

Excelをマクロ有効ブック(.xlsm)で保存する

拡張子が .xlsx のままだとマクロは保存できない。

  1. 「ファイル」→「名前を付けて保存」
  2. ファイルの種類を「Excelマクロ有効ブック (*.xlsm)」に変更
  3. 保存

手順(コピペ → 実行まで約5分)

VBE(コードを書く画面)を開く

  1. Excelで Alt + F11 を押す
  2. VBE(Visual Basic Editor)が開く

標準モジュールを挿入する

  1. VBEのメニュー →「挿入」→「標準モジュール」
  2. 白い画面(コードウィンドウ)が表示される

コードを貼り付けて実行する

  1. コードウィンドウに、下のコードをそのままコピペする
  2. コード内の書き換えポイント(★マーク)を自分の環境に合わせて変更する
  3. Alt + F8 → マクロ名を選んで「実行」

コード(最小版)– 文字列⇔数値の型変換を確認する

まず各関数の動作を確認する。イミディエイトウィンドウ(Ctrl + Gで表示)に結果が出力される。


Sub 型変換の動作確認()
    Dim s1 As String
    Dim s2 As String

    ' ★ 文字列結合 vs 数値加算
    '   VBAの + 演算子は、String型の変数同士だと「結合」になる
    '   数値リテラル同士なら「加算」になる
    '   この違いがCSV取り込み後の計算トラブルの原因
    Debug.Print "=== 文字列結合 vs 数値加算 ==="
    s1 = "1"
    s2 = "2"
    Debug.Print "s1 + s2 = " & (s1 + s2)                 ' → "12"(文字列結合)
    Debug.Print "1 + 2 = " & (1 + 2)                      ' → 3(数値加算)
    Debug.Print "CLng(s1) + CLng(s2) = " & (CLng(s1) + CLng(s2))  ' → 3(型変換後に加算)

    ' ★ CStr: 数値 → 文字列
    Debug.Print "=== CStr(数値→文字列) ==="
    Debug.Print "CStr(123) = " & CStr(123)                 ' → "123"
    Debug.Print "TypeName = " & TypeName(CStr(123))        ' → "String"

    ' ★ CInt: 文字列 → Integer(-32768〜32767)
    Debug.Print "=== CInt(文字列→Integer) ==="
    Debug.Print "CInt(""123"") = " & CInt("123")           ' → 123
    Debug.Print "TypeName = " & TypeName(CInt("123"))      ' → "Integer"
    ' CInt("32768") → オーバーフロー!(範囲外)

    ' ★ CLng: 文字列 → Long(約±21億)
    Debug.Print "=== CLng(文字列→Long) ==="
    Debug.Print "CLng(""32768"") = " & CLng("32768")       ' → 32768(CIntでは溢れるがCLngならOK)
    Debug.Print "TypeName = " & TypeName(CLng("32768"))    ' → "Long"

    ' ★ CDbl: 文字列 → Double(小数あり)
    Debug.Print "=== CDbl(文字列→Double) ==="
    Debug.Print "CDbl(""123.45"") = " & CDbl("123.45")     ' → 123.45
    Debug.Print "TypeName = " & TypeName(CDbl("123.45"))   ' → "Double"

    ' ★ Val: 先頭から数値部分だけ変換
    Debug.Print "=== Val(先頭から数値部分だけ) ==="
    Debug.Print "Val(""123"") = " & Val("123")             ' → 123
    Debug.Print "Val(""123abc"") = " & Val("123abc")       ' → 123(途中の文字以降は無視)
    Debug.Print "Val(""abc123"") = " & Val("abc123")       ' → 0(先頭が数値でなければ0)

    ' ★ IsNumeric: 数値に変換できるか判定
    Debug.Print "=== IsNumeric(数値判定) ==="
    Debug.Print "IsNumeric(""123"") = " & IsNumeric("123")       ' → True
    Debug.Print "IsNumeric(""abc"") = " & IsNumeric("abc")       ' → False
    Debug.Print "IsNumeric("""") = " & IsNumeric("")             ' → False

    ' ★ TypeName: 型の確認
    Debug.Print "=== TypeName(型の確認) ==="
    Debug.Print "TypeName(123) = " & TypeName(123)          ' → "Integer"
    Debug.Print "TypeName(""123"") = " & TypeName("123")    ' → "String"
    Debug.Print "TypeName(123.45) = " & TypeName(123.45)    ' → "Double"

    MsgBox "イミディエイトウィンドウ(Ctrl+G)に結果を出力しました。"
End Sub

実行結果(イミディエイトウィンドウ)


=== 文字列結合 vs 数値加算 ===
s1 + s2 = 12
1 + 2 = 3
CLng(s1) + CLng(s2) = 3
=== CStr(数値→文字列) ===
CStr(123) = 123
TypeName = String
=== CInt(文字列→Integer) ===
CInt("123") = 123
TypeName = Integer
=== CLng(文字列→Long) ===
CLng("32768") = 32768
TypeName = Long
=== CDbl(文字列→Double) ===
CDbl("123.45") = 123.45
TypeName = Double
=== Val(先頭から数値部分だけ) ===
Val("123") = 123
Val("123abc") = 123
Val("abc123") = 0
=== IsNumeric(数値判定) ===
IsNumeric("123") = True
IsNumeric("abc") = False
IsNumeric("") = False
=== TypeName(型の確認) ===
TypeName(123) = Integer
TypeName("123") = String
TypeName(123.45) = Double

String型の変数 s1 + s212(文字列結合)になっている点に注目。VBAの + 演算子は、String型同士だと結合として動作する。数値として加算したい場合は CLng(s1) + CLng(s2) のように型変換してから計算する。なお、VBAはリテラル文字列同士の + で暗黙的に数値変換を試みることがあるため、変数の型宣言が重要になる。

動作確認

  1. マクロを実行する
  2. 「イミディエイトウィンドウに結果を出力しました」のメッセージが出る
  3. Ctrl + G でイミディエイトウィンドウを表示して結果を確認する

最小版で各関数の動作が確認できたら、次の実務版に進む。


コード(実務版)– CSVから取り込んだデータの型変換を一括処理

自分はこの方法で毎月のCSVデータ取り込み後の型変換を処理している。SUM関数が0になる問題が完全になくなった。

指定列の文字列型数値を一括で正しい数値に変換する。全角数字やカンマ区切りにも対応。CSVの取り込み方法そのものはCSVファイルをVBAで取り込む方法を参照。


Sub 文字列型数値を一括変換()
    Dim ws As Worksheet
    Dim lastRow As Long
    Dim i As Long
    Dim col As Long
    Dim cellVal As String
    Dim cnt As Long
    Dim skipCnt As Long

    ' ★ 対象シートを指定
    Set ws = ActiveSheet

    ' ★ 変換対象の列番号を指定(B列=2, C列=3 など)
    col = 2

    ' ★ 最終行を取得
    lastRow = ws.Cells(ws.Rows.Count, col).End(xlUp).Row

    If lastRow < 2 Then
        MsgBox "データがありません。", vbExclamation
        Exit Sub
    End If

    ' 確認ダイアログ
    If MsgBox((lastRow - 1) & " 件のデータを数値に変換します。" & vbCrLf & _
              "対象列: " & col & " 列目" & vbCrLf & vbCrLf & _
              "実行しますか?", vbYesNo + vbQuestion) = vbNo Then
        Exit Sub
    End If

    On Error GoTo ErrHandler
    Application.ScreenUpdating = False

    For i = 2 To lastRow
        ' 空セルはスキップ
        If ws.Cells(i, col).Value = "" Then GoTo NextRow

        ' セルの値を文字列として取得
        cellVal = CStr(ws.Cells(i, col).Value)

        ' ★ 全角数字を半角に変換
        cellVal = StrConv(cellVal, vbNarrow)

        ' ★ カンマを除去("1,234" → "1234")
        cellVal = Replace(cellVal, ",", "")

        ' ★ 前後の空白を除去
        cellVal = Trim(cellVal)

        ' IsNumericで数値に変換できるかチェック
        If IsNumeric(cellVal) Then
            ' 小数点があればDouble、なければLongで変換
            If InStr(cellVal, ".") > 0 Then
                ws.Cells(i, col).Value = CDbl(cellVal)
            Else
                ' Long型の範囲(約±21億)を超える場合はDoubleで変換
                If CDbl(cellVal) > 2147483647 Or CDbl(cellVal) < -2147483648# Then
                    ws.Cells(i, col).Value = CDbl(cellVal)
                Else
                    ws.Cells(i, col).Value = CLng(cellVal)
                End If
            End If
            cnt = cnt + 1
        Else
            skipCnt = skipCnt + 1
        End If
NextRow:
    Next i

    Application.ScreenUpdating = True

    MsgBox cnt & " 件を数値に変換しました。" & vbCrLf & _
           skipCnt & " 件をスキップしました(数値に変換できない値)。", vbInformation
    Exit Sub

ErrHandler:
    Application.ScreenUpdating = True
    MsgBox "エラーが発生しました。" & vbCrLf & _
           "行番号: " & i & vbCrLf & _
           Err.Description, vbCritical
End Sub

書き換えポイント

# 書き換え箇所 初期値 説明
1 ActiveSheet アクティブシート 対象シート。Worksheets("Sheet1")のようにシート名で指定も可
2 col = 2 2(B列) 変換対象の列番号。C列なら3、D列なら4
3 StrConv(cellVal, vbNarrow) 全角→半角変換あり 全角数字がない場合は削除してもOK
4 Replace(cellVal, ",", "") カンマ除去あり カンマ区切りがない場合は削除してもOK

実務版で追加した機能

機能 説明 参考記事
全角→半角変換 StrConvで全角数字を半角に変換 全角半角を変換する方法
カンマ除去 Replaceで”1,234″→”1234″に変換 文字列を置換する方法
IsNumericチェック 数値に変換できない値はスキップ エラー処理の方法
型の自動判定 小数点ありならCDbl、なしならCLng
スキップ件数の通知 変換できなかった件数も表示
エラー復帰 On Error GoTo ErrHandlerでScreenUpdating復帰 エラー処理の方法

型変換関数の一覧と使い分け

主要関数の比較表

関数 方向 戻り型 特徴 注意点
CStr(値) 数値→文字列 String 数値を文字列に変換 書式は付かない(カンマなし)
CInt(値) 文字列→数値 Integer -32768〜32767の整数 32767を超えるとオーバーフロー
CLng(値) 文字列→数値 Long 約±21億の整数 VBAでは整数にはCLngが安全
CDbl(値) 文字列→数値 Double 小数を含む数値 浮動小数点の誤差あり
Val(値) 文字列→数値 Double 先頭から数値部分だけ変換 途中文字で切れる。全角は0
IsNumeric(値) 判定 Boolean 数値に変換できるかチェック 全角数字やカンマもTrue
TypeName(値) 確認 String 値の型名を返す デバッグ用。変換はしない

使い分けの結論

やりたいこと 使う関数
数値を文字列に変換 CStr(値)
文字列を整数に変換 CLng(値) (CIntはオーバーフローしやすい)
文字列を小数付き数値に変換 CDbl(値)
先頭の数値部分だけ取り出す Val(値) (ただし落とし穴あり)
変換前に数値かどうか確認 IsNumeric(値) → True なら変換OK
今の型が何か確認 TypeName(値)
数値をカンマ区切りの文字列にする Format(値, "#,##0")

重要: VBAでは整数に CInt ではなく CLng を使う。CIntは32767までしか扱えず、業務データでは簡単にオーバーフローする。

数値を書式付き文字列に変換する場合

CStrはカンマや小数桁の書式を付けない。書式付き文字列にしたい場合は日付や数値の表示形式をFormatで自由に変換する方法のFormat関数を使う。


Debug.Print CStr(1234567)               ' → "1234567"(書式なし)
Debug.Print Format(1234567, "#,##0")     ' → "1,234,567"(カンマ区切り)
Debug.Print Format(0.15, "0.0%")         ' → "15.0%"(パーセント表示)

よくある落とし穴5選

# 症状 原因 対策
1 String型の変数同士で + を使ったら結合になった VBAの + 演算子はString型同士だと文字列結合になる。CSVから取り込んだ値はString型で格納されることが多い CLng(値)CDbl(値) で型変換してから加算する。文字列結合には & を使い、+ は数値加算専用にする
2 CInt("32768") でオーバーフローエラー(実行時エラー6) CIntの範囲はInteger型(-32768〜32767)。32767を超えるとエラー 整数には CLng(約±21億)を使う。小数があるなら CDbl
3 Val("123abc")123 になる Val関数は先頭から数値として読める部分だけを返し、文字以降は無視する IsNumeric で事前チェックしてから CLngCDbl で変換する
4 Val("123")0 になる Val関数は全角数字を認識しない。一方 IsNumeric("123") は True になるので、判定と変換で結果が不整合になる StrConv(値, vbNarrow) で全角→半角に変換してから型変換する。全角半角の変換は全角半角を変換する方法を参照
5 CDbl("1,234") がエラーになる CDblはカンマ入り文字列を変換できない。IsNumeric("1,234") は True なので、判定は通るのに変換でエラーになる Replace(値, ",", "") でカンマを除去してから CDbl で変換する。文字列置換の詳細は文字列を置換する方法を参照

Val("123abc") が 123 になると知らずに使っていて、郵便番号のデータで間違った数値に変換してしまったことがある。Val関数は「ゆるい変換」なので、正確な変換には必ず IsNumeric で事前チェックしてから CLngCDbl を使う。


FAQ

Q1. CIntとCLngの違いは?どちらを使えばいい?

CIntはInteger型(-32768〜32767)、CLngはLong型(約±21億)。32767を超える数値にCIntを使うとオーバーフローエラー(実行時エラー6)になる。VBAでは基本的にCLngを使うのが安全。


Debug.Print CInt("100")    ' → 100(OK)
Debug.Print CInt("32767")  ' → 32767(OK: CIntの上限)
' CInt("32768")            ' → オーバーフロー!(実行時エラー6)
Debug.Print CLng("32768")  ' → 32768(OK: CLngなら問題なし)

Q2. Val関数とCDblの違いは?

Valは先頭から数値部分だけ取り出す(”123abc”→123)。CDblは数値に変換できない文字列だとエラーになる。正確な変換にはCDbl、ゆるい変換にはValを使うが、IsNumericで事前チェックするのが最も安全。


Debug.Print Val("123abc")   ' → 123(文字以降を無視)
' CDbl("123abc")            ' → 型の不一致エラー!
Debug.Print CDbl("123.45")  ' → 123.45(正確に変換)

Q3. セルの左上に緑の三角マークが出る。何が原因?

「数値が文字列として保存されています」の警告。CSV取り込みや先頭アポストロフィで文字列型になっている。VBAで CDblCLng で変換すれば数値に戻る。


' セルA2の値を数値に変換して書き戻す
If IsNumeric(Range("A2").Value) Then
    Range("A2").Value = CDbl(Range("A2").Value)
End If

Q4. 文字列結合には + と & のどちらを使う?

& を使う。+ は型によって加算になったり結合になったりするため意図が曖昧になる。文字列結合には常に & を使い、+ は数値加算にだけ使う。


Dim s As String
s = "100"

' 推奨: & で文字列結合
Debug.Print "合計: " & s    ' → "合計: 100"

' 非推奨: + だとString型同士は結合になる
Debug.Print s + "200"       ' → "100200"(結合)
Debug.Print CLng(s) + 200   ' → 300(型変換後に加算)

Q5. CSVファイルを取り込んだら数値が全部文字列になった。どうすればいい?

VBAでCSVを取り込む方法によっては全列が文字列型になる。取り込み後に実務版コードで対象列を一括変換するのが確実。取り込み自体の方法はCSVファイルをVBAで取り込む方法を参照。

複数列をまとめて変換したい場合は、列番号を配列で指定してループする。


Sub 複数列を一括変換()
    Dim ws As Worksheet
    Dim lastRow As Long
    Dim i As Long
    Dim c As Variant
    Dim cellVal As String
    Dim targetCols As Variant

    Set ws = ActiveSheet
    ' ★ 変換対象の列番号を指定
    targetCols = Array(2, 3, 4)  ' B列, C列, D列

    For Each c In targetCols
        lastRow = ws.Cells(ws.Rows.Count, CLng(c)).End(xlUp).Row
        For i = 2 To lastRow
            If ws.Cells(i, CLng(c)).Value <> "" Then
                cellVal = CStr(ws.Cells(i, CLng(c)).Value)
                cellVal = StrConv(cellVal, vbNarrow)
                cellVal = Replace(cellVal, ",", "")
                cellVal = Trim(cellVal)
                If IsNumeric(cellVal) Then
                    ws.Cells(i, CLng(c)).Value = CDbl(cellVal)
                End If
            End If
        Next i
    Next c

    MsgBox "変換が完了しました。"
End Sub

まとめ

この記事では、VBAで文字列と数値の型変換を正しく行う方法を解説した。

  • 最小版: 各型変換関数の動作をイミディエイトウィンドウで確認
  • 実務版: CSVから取り込んだ文字列型数値を一括で数値に変換

最も重要なポイントは 文字列の “100” と数値の 100 は VBA にとって別物 であること。文字列同士の + は結合になるため、計算する前に型変換が必要。整数には CLng、小数には CDbl を使い、変換前に IsNumeric でチェックする。

テスト用のダミーデータで動作確認してから、本番データで実行すること。

関連記事


次にやりたくなること

コメント

タイトルとURLをコピーしました