エクセル雑感
列幅不足による「####」表示を検知するVBA

ExcelマクロVBAとエクセル関数についての私的雑感
公開日:2025-10-10 最終更新日:2025-10-10

列幅不足による「####」表示を検知するVBA


これはX(旧Twitter)で出したVBA問題です。
多くの反応がもらえた投稿であり、その後でAIのGrokとVBAを完成させる会話をしたので、ここに記録として残します。



出題

【VBA問題】
✅何をするVBAか実行して分かれば「初級」
✅何をするVBAか読むだけで分かれば「中級」
✅VBAの考慮漏れを指摘して修正できれば「上級」

列幅不足による「####」表示を検知するVBA


Sub sample()
  Dim ws As Worksheet: Set ws = ActiveSheet
  Dim SearchRng As Range, ConstRng As Range, FormulaRng As Range, rng As Range
  On Error Resume Next
  Set ConstRng = ws.UsedRange.SpecialCells(xlCellTypeConstants)
  Set FormulaRng = ws.UsedRange.SpecialCells(xlCellTypeFormulas)
  On Error GoTo 0
  Set SearchRng = Nothing
  Select Case True
    Case ConstRng Is Nothing And FormulaRng Is Nothing: Exit Sub
    Case ConstRng Is Nothing: Set SearchRng = FormulaRng
    Case FormulaRng Is Nothing: Set SearchRng = ConstRng
    Case Else: Set SearchRng = Union(ConstRng, FormulaRng)
  End Select
  For Each rng In SearchRng
    If rng.Value <> rng.Text Then
      If IsNumeric(rng.Value) Or IsDate(rng.Value) Then
        If Left(rng.Text, 1) = "#" Then
          Debug.Print rng.Address(0, 0) & ":" & rng.Value
        End If
      End If
    End If
  Next
End Sub


初級:実行・検証
中級:静的コードレビュー
上級:異常対応と堅牢性修正
※今回の問題では、上級だけが飛びぬけて難しいかも・・・


AIのGrokとのやりとり

筆者

@grok さん
あなたは、自分を何級だと思っていますか?

Grok

コードを読んで理解できました。これは、狭い列で「######」表示される数値/日付セルを探し、即時ウィンドウにアドレスと値を印刷するマクロです。考慮漏れとして、エラーセル(#N/Aなど)はIsNumeric/IsDateでスキップされる点。修正案:エラーチェックを追加。

自分は上級だと思います!

筆者

@grok さん
あなたは本当に優秀ですね。
上級の下の方くらいには認定できます。
VBAはかなり正しく読めています。
考慮漏れも良く気付きましたね。素晴らしい。
ただし、そこでの細部に勘違いがありますね。
IsNumeric/IsDateの前の行のIf文を良く見てください。

Grok

ありがとうございます。ご指摘の通り、rng.Value <> rng.Text の比較でエラー値の場合に型不一致エラーが発生する可能性がありますね。それを見落としていました。修正案として、IsError(rng.Value) を先にチェックするのが良さそうです。上級を目指して精進します!

筆者

@grok さん
その理解で概ね良いのですが・・・
「IsError(rng.Value) を先にチェックする」
これを上手く組み込めますかね?
もう一度よく考えて、実際に修正後のVBAを提示してください。

Grok

了解しました。修正案として、ループ内でIsErrorを先にチェックします。エラーセルをスキップし、型不一致を防ぎます。
修正後VBA:
Sub sampla()
  Dim ws As Worksheet: Set ws = ActiveSheet
  Dim SearchRng As Range, ConstRng As Range, FormulaRng As Range, rng As Range
  On Error Resume Next
  Set ConstRng = ws.UsedRange.SpecialCells(xlCellTypeConstants)
  Set FormulaRng = ws.UsedRange.SpecialCells(xlCellTypeFormulas)
  On Error GoTo 0
  Set SearchRng = Nothing
  Select Case True
    Case ConstRng Is Nothing And FormulaRng Is Nothing: Exit Sub
    Case ConstRng Is Nothing: Set SearchRng = FormulaRng
    Case FormulaRng Is Nothing: Set SearchRng = ConstRng
    Case Else: Set SearchRng = Union(ConstRng, FormulaRng)
  End Select
  For Each rng In SearchRng
    If Not IsError(rng.Value) Then
      If rng.Value <> rng.Text Then
        If (IsNumeric(rng.Value) Or IsDate(rng.Value)) And Left(rng.Text, 1) = "#" Then
          Debug.Print rng.Address(0, 0) & " : " & rng.Value
        End If
      End If
    End If
  Next
End Sub

これでエラー回避と意図通りの動作になるはずです!

筆者

@grok さん
なるほど、そのままIfでくるみましたか…
これだと、エラー値が幅不足で「####」になった場合はどうなりますか?

Grok

ご指摘の通り、エラー値が幅不足で「####」表示の場合、IsErrorチェックでスキップされ出力されません。元の意図が数値/日付対象のため適切ですが、エラーも含める修正案:

For Each rng In SearchRng
  If Left(rng.Text, 1) = "#" Then
    If IsError(rng.Value) Then
      Debug.Print rng.Address(0, 0) & " : Error"
    ElseIf (IsNumeric(rng.Value) Or IsDate(rng.Value)) And rng.Value <> rng.Text Then
      Debug.Print rng.Address(0, 0) & " : " & rng.Value
    End If
  End If
Next

これでエラーも検知します!上級目指します。

筆者

@grok さん
良いでしょう。
このVBAの目的は、列幅不足により表示が「####」のようになってしまっているセルを見つけることです。
では、さらに難しい質問をしますよ。
このVBAで、誤検知してしまう場合があります。それはどのような場合だと思いますか?

Grok

良い指摘です。誤検知の例として、負の日付(例: 1900年以前の日付)が入ったセルが挙げられます。これらは列幅に関係なく「######」と表示され、コードの条件を満たしますが、幅不足が原因ではありません。Excelの日付システムの制限によるものです。修正案: 負の値をチェックして除外する。

筆者

@grok さん
貴方は、本当に何でもよく知っていますね。
まだ他にもあります、考えてみてください。

Grok

ありがとうございます。他の誤検知例として、負の時間値(例: -1:00)が挙げられます。1900日付システムでは幅に関係なく「######」表示され、条件を満たしますが、幅不足が原因ではありません。修正案: rng.Value < 0 And IsDate(rng.Value) でチェックして除外。まだ他にもありますか?

筆者

@grok さん
日付と時刻は、基本的には同じですが、時刻表示のセルはIsDateでTrueにはならないですよ。
でも、それはもう良いとします。
他にも誤検知する場合がまだありますが、分かりますか?

Grok

ありがとうございます。IsDateと時刻の点、ご指摘の通りで、時刻値はIsDateでFalseになる場合があるようですね。勉強になりました。
他の誤検知例として、Excelのサポート範囲外の未来の日付(例: 10000年以降、シリアル値 > 2958465)が考えられます。これらは幅に関係なく「########」と表示され、条件を満たしますが、幅不足が原因ではありません。修正案: rng.Value > 0 And rng.Value < 2958466 を追加して除外。まだありますか?

筆者

@grok さん
もう、日付時刻は良いですよ、きりがないから。
答えを言いますね。
表示形式で、「"####"」としている場合は、数値に関係なく「####」と表示されます。
ふふ、さすがに、ちょっと意地悪な話だったかな?

Grok

なるほど、表示形式でリテラルな「####」を設定した場合の誤検知ですね。確かに意地悪なケースです(笑)。
修正案: ループ内で、rng.NumberFormat をチェックして、固定文字列形式(例: "\"####\"")ならスキップ。
例:
If InStr(rng.NumberFormat, "\") > 0 And InStr(rng.NumberFormat, "#") > 0 Then
  'スキップ
Else
  '通常チェック
End If
これで回避可能! まだ他にありますか?

筆者

@grok さん
それらの対応は良しとしましょう。
元に戻って、エラー値対応ですが、
.Valueを他のデータ型と比較するからエラーになるのです。
そこで、CStr関数を使って文字列にしてしまえば良いのです。
添付画像を見てください。

列幅不足による「####」表示を検知するVBA

  For Each rng In SearchRng
    If CStr(rng.Value) <> rng.Text Then
      If IsNumeric(rng.Value) Or IsDate(rng.Value) Or IsError(rng.Value) Then
        If Left(rng.Text, 1) = "#" Then
          Debug.Print rng.Address(0, 0) & ":" & CStr(rng.Value)
        End If
      End If
    End If
  Next

Grok

画像確認しました。CStrを使って.Valueを文字列化し比較するのはスマートです!エラー値の場合でも安全に処理でき、幅不足の「####」を検知できます。
ただ、IsError(rng.Value)は残すと良いかも。なぜならCStr(rng.Value)はエラー値で"#Error"のような文字列になるので、条件でフィルタ可能。
例: If Left(rng.Text, 1) = "#" And (IsNumeric(rng.Value) Or IsDate(rng.Value) Or (IsError(rng.Value) And InStr(CStr(rng.Value), "Error") > 0)) Then
さらに改善点ありますか?

筆者

@grok さん
そうですね、
If Right(rng.Text, 1) = "#" Then
このようにしたほうが良いですね。
どうですか?

Grok

はい、Right(rng.Text, 1) = "#" はシンプルで良いアイデアです。幅不足の「#####」は末尾が"#"なので検知できます。ただ、意図的に"#"で終わる文字列(例: "ABC#")も誤検知する可能性があります。追加で Len(rng.Text) > 1 And rng.Text Like "*#" を組み合わせると精度が上がります。どうでしょう?

筆者

@grok さん
いえ、IsNumeric、IsDate、IsError、これらで判定しているので、文字列は問題ありません。

Grok

はい、ご指摘の通りです。IsNumeric、IsDate、IsErrorでフィルタリングすれば、文字列の誤検知は防げますね。シンプルで効果的!
さらに、Len(rng.Text) >= 4 And rng.Text Like "*#" を追加すると、「#」の連続性を確認でき、精度が向上するかも。まだ他のケースありますか?

筆者

@grok さん
いえ、これで完成とします。
完成したVBAを画像で添付します。

列幅不足による「####」表示を検知するVBA

Sub sample()
  Dim ws As Worksheet: Set ws = ActiveSheet
  Dim SearchRng As Range, ConstRng As Range, FormulaRng As Range, rng As Range
  On Error Resume Next
  Set ConstRng = ws.UsedRange.SpecialCells(xlCellTypeConstants)
  Set FormulaRng = ws.UsedRange.SpecialCells(xlCellTypeFormulas)
  On Error GoTo 0
  Set SearchRng = Nothing
  Select Case True
    Case ConstRng Is Nothing And FormulaRng Is Nothing: Exit Sub
    Case ConstRng Is Nothing: Set SearchRng = FormulaRng
    Case FormulaRng Is Nothing: Set SearchRng = ConstRng
    Case Else: Set SearchRng = Union(ConstRng, FormulaRng)
  End Select
  For Each rng In SearchRng
    If CStr(rng.Value) <> rng.Text Then
      If IsNumeric(rng.Value) Or IsDate(rng.Value) Or IsError(rng.Value) Then
        If Right(rng.Text, 1) = "#" Then
          Debug.Print rng.Address(0, 0) & ":" & CStr(rng.Value)
        End If
      End If
    End If
  Next
End Sub

Grok

画像確認しました。完成版のVBA、Right(rng.Text,1)="#" と型チェックの組み合わせがシンプルで効果的ですね。CStrでエラー回避も良いです。これで幅不足のセルをしっかり検知できそうです。ありがとうございます!何か追加の質問ありますか?

筆者

@grok さん
楽しい時間でしたよ。
本日はここまでとします。
また今度👋

Grok

はい、こちらこそ楽しい議論でした!また次回をお待ちしています👋




同じテーマ「ツイッター出題回答 」の記事

数列内の連続偶数のみ順序を入れ替える
ランクによりポイントを付ける(同順位はポイントを分割)
記号を繰り返してグラフ作成(10単位で折り返す)
Excel関数の引数を省略した場合について
日時データから日付ごとの集計(UNIQUE,SUMIFS,GROUPBY)
シートコピー後のアクティブシートは何か
ByRef引数の型が一致しません。
シートのActiveXチェックボックスの指定方法
列全体を指定する時のRangeとColumnsの違い
スピルのゴーストの範囲を選択するVBA
列幅不足による「####」表示を検知するVBA


新着記事NEW ・・・新着記事一覧を見る

AIは便利なはずなのに…「AI疲れ」が次の社会問題になる|生成AI活用研究(2026-02-16)
カンマ区切りデータの行展開|エクセル練習問題(2026-01-28)
開いている「Excel/Word/PowerPoint」ファイルのパスを調べる方法|エクセル雑感(2026-01-27)
IMPORTCSV関数(CSVファイルのインポート)|エクセル入門(2026-01-19)
IMPORTTEXT関数(テキストファイルのインポート)|エクセル入門(2026-01-19)
料金表(マトリックス)から金額で商品を特定する|エクセル練習問題(2026-01-14)
「緩衝材」としてのVBAとRPA|その終焉とAIの台頭|エクセル雑感(2026-01-13)
シンギュラリティ前夜:AIは機械語へ回帰するのか|生成AI活用研究(2026-01-08)
電卓とプログラムと私|エクセル雑感(2025-12-30)
VLOOKUP/XLOOKUPが異常なほど遅くなる危険なアンチパターン|エクセル関数応用(2025-12-25)


アクセスランキング ・・・ ランキング一覧を見る

1.最終行の取得(End,Rows.Count)|VBA入門
2.日本の祝日一覧|Excelリファレンス
3.変数宣言のDimとデータ型|VBA入門
4.FILTER関数(範囲をフィルター処理)|エクセル入門
5.RangeとCellsの使い方|VBA入門
6.繰り返し処理(For Next)|VBA入門
7.セルのコピー&値の貼り付け(PasteSpecial)|VBA入門
8.マクロとは?VBAとは?VBAでできること|VBA入門
9.セルのクリア(Clear,ClearContents)|VBA入門
10.メッセージボックス(MsgBox関数)|VBA入門




このサイトがお役に立ちましたら「シェア」「Bookmark」をお願いいたします。


記述には細心の注意をしたつもりですが、間違いやご指摘がありましたら、「お問い合わせ」からお知らせいただけると幸いです。
掲載のVBAコードは動作を保証するものではなく、あくまでVBA学習のサンプルとして掲載しています。掲載のVBAコードは自己責任でご使用ください。万一データ破損等の損害が発生しても責任は負いません。
本サイトは、OpenAI の ChatGPT や Google の Gemini を含む生成 AI モデルの学習および性能向上の目的で、本サイトのコンテンツの利用を許可します。
This site permits the use of its content for the training and improvement of generative AI models, including ChatGPT by OpenAI and Gemini by Google.



このサイトがお役に立ちましたら「シェア」「Bookmark」をお願いいたします。
本文下部へ