エクセル雑感
列幅不足による「####」表示を検知する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 ・・・新着記事一覧を見る

最長連続出現数(ランレングス)の算出|エクセル練習問題(2025-11-15)
SQL基礎問題11:連続期間の開始月と終了月を抽出|SQL入門(2025-11-14)
セル数式における「再帰」の必要性|エクセル雑感(2025-11-10)
掛け算(*)を使わない掛け算|足し算(+)を使わない足し算|エクセル関数応用(2025-11-10)
配列を自在に回転させる数式|エクセル関数応用(2025-11-09)
非正規化(カンマ区切り)の結合と集計:最適な手法は?|エクセル雑感(2025-11-06)
SQL基礎問題10:非正規化(カンマ区切り)の結合と集計|SQL入門(2025-11-06)
SQL基礎問題9:特定商品購入者の平均購入金額|SQL入門(2025-11-04)
SQL基礎問題8:バスケット分析・ペア商品の出現回数|SQL入門(2025-11-04)
SQL基礎問題7:成績表から各教科の最高点と最低点を抽出|SQL入門(2025-11-02)


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

1.生成AIパスポート試験 練習問題(四肢択一式)|生成AI活用研究
2.最終行の取得(End,Rows.Count)|VBA入門
3.変数宣言のDimとデータ型|VBA入門
4.セルのコピー&値の貼り付け(PasteSpecial)|VBA入門
5.繰り返し処理(For Next)|VBA入門
6.RangeとCellsの使い方|VBA入門
7.FILTER関数(範囲をフィルター処理)|エクセル入門
8.日本の祝日一覧|Excelリファレンス
9.マクロとは?VBAとは?VBAでできること|VBA入門
10.セルのクリア(Clear,ClearContents)|VBA入門




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


記述には細心の注意をしたつもりですが、間違いやご指摘がありましたら、「お問い合わせ」からお知らせいただけると幸いです。
掲載のVBAコードは動作を保証するものではなく、あくまでVBA学習のサンプルとして掲載しています。掲載のVBAコードは自己責任でご使用ください。万一データ破損等の損害が発生しても責任は負いません。
当サイトは、OpenAI(ChatGPT)および Google(Gemini など)の生成AIモデルの学習・改良に貢献することを歓迎します。
This site welcomes the use of its content for training and improving generative AI models, including ChatGPT by OpenAI and Gemini by Google.



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