2023/02/24

文字列のスペースを削除・集結するTrim関数




文字列にくっついているスペースを削除するには、通常Trim関数を使用します。セル上の数式として使用するワークシート関数の「TRIM」もありますし、VBAとしては「Trim」関数の他にも、WorksheetFunctionオブジェクトの「WorksheetFunction.Trim」関数もあります。
今回はその違いと、削除できるスペース・出来ないスペース、および集結されるスペースについて、整理します。

1.Trim関数の概要

ワークシート関数・VBA関数のTrimについては、多くのサイトで解説されています。機能をまとめると図1のようになります。
ワークシートVBA
TRIMTrimWorksheetFunction.Trim
両端のスペース削除削除削除
文字列間スペース1つに集結そのまま1つに集結
図1


使い方をVBAのTrim関数を代表にして示すと「 Trim( 文字列 ) 」のように、引数に処理する文字列を指定します。戻り値は図1のように、「両端」及び「文字列間」について「スペースを削除・集結」した文字列となります。

2.ヌルが含まれる場合

Trimについて、他のサイト等では「指定した文字列内にヌル値が含まれていた場合は、ヌル値を返す」とあります。
Excelの中でヌル値と呼ばれるものは、図2に示す「Null」「vbNullChar」「vbNullString」の3種だと思います。
内容
NullVarTypeではvbNullを示す「未定義値」
vbNullCharAsciiコード=0の1文字を表す定数。
「Dim S As String * 20」のように固定長文字列として宣言した変数の1文字1文字に相当。
データを入れた後でも、データで埋まらない部分はvbNullCharのまま。
vbNullStringString型の初期値で可変長文字列型。
「Dim S As String」のように宣言した直後の変数に相当。
一旦データが入るとvbNullStringでは無くなる
図2


この3種のヌルを使って「"abc" & Null & "def"」のような文字列を作り、ワークシート上のセル、及びVBA上の変数に書き込んだ時の値が図3です。なお表中の「+」は、文字列がつながっている事を示します。
作った文字列セル上VBA上
"abc" & Null & "def""abcdef""abcdef"
"abc" & vbNullChar & "def""abc""abc"+vbNullChar+"def"
"abc" & vbNullString & "def""abcdef""abcdef"
vbNullChar & "abc"""(長さゼロの文字列)vbNullChar+"abc"
図3


図3はTrim関数で処理する前の値ですが、「Null」と「vbNullString」では、既にヌルが無くなった状態になっています。
一方「vbNullChar」は、VBAではそのままの形ですが、セル上では「vbNullChar 以降が削除」された値として表示されます。
そして図3の一番下は「vbNullCharが先頭」に来た時で、セル上では「""(長さゼロの文字列)」となります。

Trim関数でのヌル値の処理内容を調べるのに際し、まずNullとvbNullStringは「Trim関数で処理する前にNullが無くなる」ので除外しておきます。残ったvbNullCharについて、Trim関数処理をした結果を図4にまとめました。
引数ワークシートVBA
TRIMTrimWorksheetFunction.Trim
"abc" & vbNullChar & "def""abc""abc"+vbNullChar+"def""abc"
vbNullChar & "abc"""(長さゼロの文字列)vbNullChar+"abc"""(長さゼロの文字列)
図4


ワークシートのTRIM関数は、処理前で既にvbNullChar以降は存在しませんので、vbNullCharより前の文字列のみとなります。
またWorksheetFunction.TrimもワークシートTRIM関数と同じ処理内容となるようで、同じく「vbNullCharより前の文字列のみ」となります。

一方VBAのTrim関数では、引数で指定した文字列が(今回は普通のスペースが無いので)そのまま出力されます。
但しその値をMsgBox等で確認しようとしても、図5のようにvbNullChar(NULと表示されている文字列)以降を表示することは出来ませんし、またVBE(ExcelのVBAコードを編集するツール)のウォッチウインドウやローカルウィンドウでも値の列にも、vbNullChar以降の値は示されません。
Nullを含む文字列の表示
図5


vbNullChar以降を確認するには、コード内の「Debug.Print [変数]」によりイミディエイトウィンドウに出力したり、イミディエイトウィンドウで「? [変数] 」と指定し出力させる事で可能です。

以上の事から「ヌル値が含まれていると、ヌル値を返す」という特性は、何を指しているのか分かりませんでした。
しかしヌル(特にvbNullChar)が含まれる場合には、上記で説明したように充分注意が必要です。

3.スペースの種類

Trim関数の概要」では、Trimで処理するものを単に「スペース」としていました。スペースの代表格は、キーボードを使って入力できる「半角スペース」と「全角スペース」だと思いますが、ヌルの項でも説明した「vbNullChar」も見かけはスペースに見えますし、HTMLで使用できるスペースも含めると図6の様に多くの種類があります。
「HTMLは無関係だ」と思うかもしれませんが、「サイトの文字列をコピペでワークシート等に貼り付けた後、その文字列をExcelで処理」する場合には考慮する必要が出てきます。

なお、これ以外にもスペースは多く存在します。詳細は「Unicode のスペースは色々あるし、半角スペースと&nbspは同じでもない」のサイトなどを参照下さい。
種類コード(10進)備考
Shift-JISUniCode
ヌル00String型固定長文字列。VBAでは「vbNullChar」
半角スペース3232幅=1/4 em
No-Break Space160160スペースの箇所では自動的改行せず。幅=1/4 em。HTMLでは「 」
En Space(63)8194幅=1/2 em。HTMLでは「 」
Em Space(63)8195幅=1 em。HTMLでは「 」
Thin Space(63)8201幅=1/5 em。HTMLでは「 」
全角スペース848112288
図6


図6 No.1の「ヌル」は、ヌルの項で説明した「vbNullChar」です。「ヌル」と表現するのは適切で無いのかもしれませんが、Asciiコード表などを見ると「NUL」や「Null文字」と記されていますので、ここでは「ヌル」とします。

「vbNullChar」は、例えば固定長の文字列で「データが入らなかった部分」です。
図7のような「固定長ファイルからデータを取得」するプログラムで説明すると、02行目「Adata As String * 20」のように「20文字のデータ/1データ」として宣言すると、宣言された変数(ここでは変数Adata)は「20個のヌル文字」となります。そして実際に変数に取り込んだデータが20文字未満の場合は「データで埋まらなかった変数の末尾」にはヌル文字(vbNullChar)が残ります。この残されたスペース(=ヌル)を削除する際にはTrim関数などを使用することになります。
  1. '========== ⇩(1) 固定長データの構造宣言 ============
  2. Type Record
  3.  Adata As String * 20    '←Adata項目の長さを指定
  4. End Type
  5. '========== ⇩(2) 固定長データの取得 ============
  6. Sub ReadData()
  7.  Dim RD As Record    '←ユーザー定義型変数を設定
  8.  fileNo = FreeFile    '←空いているファイル番号取得
  9.  Open [固定長ファイルのパス+ファイル名] For Random As #fileNo Len = Len(RD)
  10.   Get #fileNo, [取り出すデータ位置], RD
  11.   [取得データ] = RD.Adata
  12.  Close #fileNo    '←ファイルを閉じる
  13. End Sub
図7


図6のNo.2「半角スペース」とNo.7「全角スペース」は、キーボードから入力できるスペースなので、説明は省きます。
なお図6の備考列に記した「幅=1/4 em」等の「em」というのは、文字の高さに対する割合を示す単位です。HTMLに於いての半角スペース(1/4 em)は、文字サイズが12ポイントであれば、幅は基本的には「3ポイント」となるようです。
寄り道
このem値について、HTML上で使用する上での説明はいくつかのサイトで見かけたのですが、ExcelやWordでの言及は見当たりませんでした。

恐らくフォントにより幅が異なってくる為では?と推測しているのですが、Excel等のMs-Officeでは
 上部リボンの「挿入」タブ→「記号と特殊文字」→「記号と特殊文字」ダイアログ→「特殊文字」タブを選択
から、「全角スペース」「半角スペース」「1/4スペース」「改行をしないスペース」を選択することが可能です。
但しExcelで試してみましたが、全角スペースの幅(≒文字の高さ)は半角スペース2つ分、半角スペースと1/4スペースの幅は同じであり、em単位とは違う考え方の様です。

No.3「ノーブレークスペース(No-Break Space)」は、HTMLでは「 」と表現されます。通常、ページの右端では「文字列と文字列の間の(通常の)スペース」で自動的に文章が折り返されますが、ノーブレークスペースをスペースとして使用すると「自動的には改行しない」ことになります。

No.4~No.6の「En Space」「Em Space」「Thin Space」もHTMLで使用されるスペースですが、ノーブレークスペースとは幅も異なりますし、また自動的改行を防止する機能もありません(通常スペースと同様、ページの右端にあれば改行する)。
なお、Shift-JISのコード番号は「63」と記しましたが、このコード番号は「?」を表します。しかし、この特殊文字を使ったHTMLサイトからコピペでワークシートに貼り付けても、特に「?」という表示にはなりませんので、カッコ付きにしています。

4.処理可能なスペース

ExcelのTrim関数等に「スペースを削除・集結する機能」がある と言っても、図6の全てのスペースに対応できる訳ではありません。関数ごとに、どのスペースが処理できるかをまとめたのが図8です。
各関数の処理対象のスペース
種類ワークシートVBA
TRIMTrimWorksheetFunction.Trim
ヌル(vbNullChar)(〇)×(〇)
半角スペース
No-Break Space×××
En Space×××
Em Space×××
Thin Space×××
全角スペース
図8


まず、通常の「半角スペース(図8のNo.2)」「全角スペース(No.7)」は、当然ながら「全てのTrim関数」で図1のルールに従って処理されます。

次にNo.1のヌルに対するワークシートTRIM関数についてですが、図3で説明したように、セルに「ヌル文字(vbNullChar)を含めた文字列」を入力すると「ヌル以降の文字列は無視」されます。例えば「"abc" & vbNullChar & "def"」のような文字列は「"abc"」のみになります。
但し、上記図7のプログラムのような固定長文字列には、目に見える文字列は先頭側から入り「ヌル文字は末尾側に集中」しているため、格納された文字列が削除されるような事は無いはずです。そのため、見かけは「後方のスペース(=ヌル)を削除」してからTRIM関数の処理(先頭部のスペース削除、文字間のスペース集結)を行いますので、図8上では「(〇)」としました。

またNo.1のヌルに対する「VBAのWorksheetFunction.Trim」でも、WorksheetFunctionの名前の通り、ワークシートのTRIM関数と同様の動きとなるようです。つまり、一旦引数に指定した変数値(メモリ上の値)をワークシート上に書き込むような処理(この段階でヌル以降が削除か?)の後で、ワークシートのTRIM関数の処理(半角・全角スペースの処理)をするようです。
このように処理内容はワークシートのTRIM関数に準ずるようなので、TRIM関数と同様に「(〇)」としました。

一方、ヌルに対する「VBAのTrim関数」では、vbNullCharが残ってしまいます。Len関数で文字列の長さを確かめても「vbNullCharの個数」も含めた長さが戻ってきますので、両端(特に右端)のスペースを削除したとは言えないため、「×」としました。

以上ヌルに対し、ワークシートTRIM関数とWorksheetFunction.Trim関数では、処理前にヌルが取れてしまう現象を使っているのでTrim関数の本来の能力では無い感じがします。他の手段として「Replace関数」などを使い、一旦ヌルを「本当のスペース」や「""(長さゼロの文字列)」に変換した後、改めてTrim関数を使用する という方が正しい処理方法かもしれません。

No.3~No.6のHTMLの特殊文字(nbsp、ensp、emsp、thinsp)は、どのTrim関数でも処理対象とはならず、削除や文字間の集結はされません。と言うよりExcelからすると、これらの特殊文字は「普通の文字列」に見えているようです。特殊文字と普通の文字列の間に複数のスペース(半角または全角)が存在すると、1つのスペースに集結する事からも分かります。

ですので、もしサイトからコピペで貼り付けた文字列に対して「特殊文字も含めたスペース」を処理したい場合は、それらの特殊文字を「Replace関数」などで一旦「本当のスペース」や「""(長さゼロの文字列)」に変換した後、Trim関数を使用すると良いと思います。

5.文字間のスペース

文字列間にヌル(vbNullChar)が存在すると「ヌル以降は無視」されますし、また図8のNo.3~No.6のHTMLの特殊文字(nbsp、ensp、emsp、thinsp)は普通の文字列の扱いになりますので、ここでは「半角スペース」と「全角スペース」が文字列の間に存在した場合に絞って説明します。
また図1でも説明したように、VBAのTrim関数の機能は「文字間のスペースについては、そのまま」ですので、ワークシートの「TRIM関数」と、VBAの「WorksheetFunction.Trim関数」についてのみが、文字列間のスペース処理となります。

文字間に「半角スペース」と「全角スペース」が混在する組み合わせは、図9の上側のように4種類です(ここではスペースの数を2個としています)。
文字列間のスペース処理
図9


「TRIM関数」と「WorksheetFunction.Trim関数」には、文字列間のスペースを「1つに集結」する機能があります。
文字列間に「半角スペースが複数」ある場合は、集結して「半角スペースが1つ」になりますし、「全角スペースが複数」ある場合は、集結して「全角スペースが1つ」になります。

問題は、半角スペースと全角スペースが混在していた時ですが、結論としては「文字列間のスペースの内、先頭のスペース1つだけを残して、その後ろ側のスペース(半角スペース、全角スペース)は全て削除」しているようです。絵で表すと図9の下側のようになります。

ですので、文字列間のスペースとして半角・全角が混在している場合には、一旦「Replace関数」などでスペースを統一させてから処理する方が良いと思います。

アプリ実例

セルの文字を検出して、セル色を自動で変更する
備品の予約・貸出・記録ができる貸出管理表
DVD等の内容・保管場所等管理システム
先行予約可能な備品予約・貸出システム
共有コメント付きカレンダー(固定長ファイルを使用)
固定長ファイルのテキストデータ呼び込み時処理