検証環境: Excel 365 v2509 · Excel 2021 · Excel 2019 · 最終確認 2026-06-10
要点 — VBA の Trim は文字列の両端の空白を取り除くだけで、それ以外は何もしません。テキストの内側にある連続スペースをまとめることはなく、Web ページや PDF が貼り付ける非改行スペース(Chr(160))も取り除きません。この 2 つ目の事実こそ、「Trim が効かない」が VBA の検索上位の悩みであり続ける理由です。
Sub TrimDemo()
Dim s As String
s = " 山田 太郎 " ' 両端 + 真ん中に二重スペース
Debug.Print "[" & Trim(s) & "]" ' [山田 太郎] <- 両端は消えるが、内側の二重スペースは残る
Debug.Print "[" & LTrim(s) & "]" ' [山田 太郎 ] 左端だけ
Debug.Print "[" & RTrim(s) & "]" ' [ 山田 太郎] 右端だけ
End Sub
内側の連続スペースも 1 つにまとめたいときは、VBA のキーワードではなくワークシート関数を使います。
Debug.Print Application.WorksheetFunction.Trim(" 山田 太郎 ") ' "山田 太郎"
考え方の軸:Trim は「両端をそろえる」だけ、洗うわけではない
Trim は端をきれいにします。左から非空白に当たるまで進み、右から非空白に当たるまで進み、その間を返す。真ん中はそっくりそのまま残ります。これが動作のすべてで、すべての「想定外」を説明します。
このイメージを持てば、ファミリーは一目で読めます。LTrim は左端だけ、RTrim は右端だけ、Trim は両端。どれも内側には関心がありません。だから問題が「ユーザーが姓名の間に空白を 2 つ打った」なら、Trim は端的に道具ちがいです。内側の連続もまとめてくれる、同名の別関数 WorksheetFunction.Trim を使いましょう。
唯一のルール:VBA の Trim が消すのは ASCII スペース Chr(32) だけ
これが、不可解なバグを 1 行の修正に変えるルールです。
Trimが「消すべき空白」と認識する文字はただ 1 つ、ふつうの ASCII スペースChr(32)だけです。それ以外の空白に見える文字 — タブ、改行、そして何より非改行スペースChr(160)— は、Trimにとっては残すべき普通の文字です。
この罠が自然に潜む場所はこうです。Web ページ、HTML メール、PDF から値を Excel にコピーする。見た目は末尾がスペースで終わっている。Trim を実行しても、セルは相変わらず検索に一致せず、1 時間を溶かす。
Dim raw As String
raw = "山田太郎" & Chr(160) ' 末尾に非改行スペース、Web 貼り付け由来
Debug.Print Len(Trim(raw)) ' 5(4 ではない)— Trim は何も消していない
Debug.Print (Trim(raw) = "山田太郎") ' False! 値は同じに見えるが一致しない
直し方は「賢い Trim」ではありません。まず Chr(160) を本物のスペースに変えてから Trim することです。
Function CleanText(ByVal s As String) As String
s = Replace(s, Chr(160), " ") ' 非改行スペース -> 通常スペース
s = Application.WorksheetFunction.Clean(s) ' 制御文字 Chr(0)-Chr(31) を除去
CleanText = Application.WorksheetFunction.Trim(s) ' 内側の連続をまとめ、両端を Trim
End Function
ここで Clean にも触れておきます。エクスポートから紛れ込む印字不能な制御文字(復帰・改行・タブなど 0〜31 の範囲)を取り除きます — ただし Chr(160) は取り除きません。160 はその範囲の外だからです。だから実務の整形は、単独の関数ではなく、上の 3 つをこの順で重ねるのが正解です。
第 2 の罠:Trim と Trim$
Trim は 2 つあります。素の Trim は Variant 版、Trim$ は String 型の双子です。実務上の違いは 2 つ。
Trim$はわずかに速く、直接Stringを返します。数千セルを回すきついループでは効いてきます。Trim$はNullでエラーになり、TrimはNullを黙ってそのまま通します。NullになりうるVariant(データベースの項目、空のRange.Value)を読むときは、素のTrimが寛容な方です。
私の習慣は、型を自分で握っているループでは Trim$、値が Null になりうる境界では素の Trim。どちらを握っているか分かっていれば、不意の「Null の使い方が不正です」を避けられます。
どれをいつ使うか
| やりたいこと | 使うもの |
|---|---|
| 先頭と末尾の空白を消す | Trim(s) |
| 片側だけ | LTrim(s) / RTrim(s) |
| 内側の二重スペースもまとめる | Application.WorksheetFunction.Trim(s) |
| 印字不能な制御文字を消す | Application.WorksheetFunction.Clean(s) |
| Web/PDF 由来の非改行スペースを潰す | Replace(s, Chr(160), " ") の後に Trim |
| 列まるごとを速く整える | CleanText 関数 1 つを、セルごとに 1 回 |
意見:Trim を連ねるな — 境界で一度だけ正規化せよ
いちばんよく見るアンチパターンは、マクロのあちこちに守りで Trim を撒くこと — ここで Trim(rng.Value)、あそこで Trim(parts(i)) — どれかが比較をやっと通してくれるのを期待して。Chr(160) に対しては決して通りません。どの Trim もそれに触れないからです。
テキストの整形は境界の仕事で、行ごとの仕事ではありません。データが汚れて入ってくるのはただ 1 か所 — 取り込み、貼り付け、読み取り — なので、そこで一度だけ、上のような単一の CleanText 関数で整え、以降はそれを信頼します。境界で正規化するマクロは読みやすく正しい。Trim が 40 か所に散ったマクロは、作者が当てずっぽうをしていたマクロです。本物の整形をしても比較がまだ落ちるなら、その差はそもそも空白ではありません — Chr(160)、大文字小文字の不一致(CStr / 型変換 を参照)、あるいは文字列として保存された数値です。
よくある Trim のミス(と直し方)
| 症状 | 原因 | 直し方 |
|---|---|---|
| 値は「Trim 済みに見える」のに一致しない | Web/PDF 貼り付け由来の末尾 Chr(160) |
Trim の前に Replace(s, Chr(160), " ") |
| 内側の二重スペースが残る | 端しか処理しない Trim を使った |
WorksheetFunction.Trim(s) |
| 改行・タブが生き残る | それらは空白ではなく制御文字 | まず WorksheetFunction.Clean(s) |
| ループで「Null の使い方が不正です」 | Trim$ が Null の Variant に当たった |
素の Trim、または先に IsNull を判定 |
| セルに対し Trim が何もしないように見える | その空白は実は Chr(160) か Chr(9) |
Asc(Right(s,1)) で実際のコードを確認 |
| Trim 後も列全体が不一致のまま | 整形が散在し、取り込み時に行われていない | 読み取り境界で CleanText を 1 回呼ぶ |
整形が目的を上回ったら — 代わりに「やりたいこと」を伝える
あなたは空白を研究したかったわけではありません。今週のエクスポートをマスター一覧と突き合わせたかっただけなのに、半分が Chr(160) に包まれて届いたせいで名前がそろわない。整形関数を書き、列を回し、それでも一致しない 1 行を追ううちに、配管仕事が午後を食い尽くす。ExcelMaster Agent なら、自然な日本語で目的をそのまま言えます — 「B 列の空白と隠れ文字をきれいにして、マスターシートと突き合わせて」 — すると Chr(160)・制御文字・大文字小文字まで面倒を見る Python を、ブックを先にバックアップしたうえで書き出します。無料で試す →
関連ガイド
- VBA Format — 日付・数値と、書式設定が計算を壊す理由
- VBA CStr・CDate・Val — 文字列を数値・日付へ正しく変換する
- VBA InStr — 文字列の中から文字を探す
- VBA Split — 1 つの文字列を配列に変える
- VBA For ループ — 実務の 8 例
よくある質問
VBA の Trim が効かないのはなぜ?
ほとんどの場合、その「スペース」がスペースではないからです。Trim が消すのは ASCII スペース Chr(32) だけ。Web ページ・HTML メール・PDF から貼ったテキストは、末尾が非改行スペース Chr(160) で終わっていることが多く、Trim はそれを残します。先に置き換えましょう:Trim(Replace(s, Chr(160), " "))。
VBA Trim は文字列内側の二重スペースを消す?
いいえ。VBA のキーワード Trim は両端の空白しか消しません。内側の連続を 1 つのスペースにまとめるには、ワークシート関数 Application.WorksheetFunction.Trim(s) を使います。
VBA の Trim と Trim$ の違いは?
Trim は Variant を返し Null をそのまま通します。Trim$ は直接 String を返し、わずかに速く、Null でエラーになります。型が分かっているきついループでは Trim$、値が Null になりうる場所では素の Trim を使いましょう。
VBA で非改行スペース(Chr 160)を消すには?
通常のスペースに置き換えてから Trim します:Application.WorksheetFunction.Trim(Replace(s, Chr(160), " "))。同じパスで改行やタブなどの制御文字も消すなら WorksheetFunction.Clean(s) を足します。
VBA Clean は何をする? Trim と同じ?
いいえ。Clean は印字不能な制御文字(0〜31、改行やタブなど)を消し、Trim は空白を消します。別々の問題を解くもので、よく併用します。なお Clean は Chr(160) を消しません。160 は制御文字の範囲外だからです。
