[今日のトリビア][Excel VBA]vbNullChar区切りの配列をJoinすると、Null文字が勝手に空白になる vbNullChar Separeted array can make in vba, but cannot show in the cell

# VBAでもvbNullChar区切り配列は成功する
Chr(0)を区切り文字として配列を作ることが可能。

```vb
Sub ZeroDelimiterArray()
Dim ar
Dim str As String
Debug.Print "vbNull", vbNull = Chr(0)
Debug.Print "vbNullString", vbNullString = Chr(0)
Debug.Print "vbNullChar", vbNullChar = Chr(0)
Debug.Print """"" = Chr(0)", "" = Chr(0)
Debug.Print "Len(vbNullChar)", Len(vbNullChar)
Debug.Print "LenB(vbNullChar)", LenB(vbNullChar)
str = "A" & Chr(0) & "B" & Chr(0) & "C " & Chr(0) & Chr(0)
ar = Split(str, Chr(0), -1, vbBinaryCompare)
Debug.Print UBound(ar)
Dim I
For I = LBound(ar) To UBound(ar)
Debug.Print ar(I)
Next
ActiveCell.Value = Join(ar)
End Sub
```

## ImmidiateWindowの表示
イミディエイトウインドウには以下のように表示される

```text
vbNull     False
vbNullString  False
vbNullChar  True
"" = Chr(0)  False
Len(vbNullChar)          1 
LenB(vbNullChar)        2 
4 
A
B
C 
 ```

なので`vbNullChar`が`Chr(0)`ということがわかる。
[その他の定数](https://docs.microsoft.com/ja-jp/office/vba/language/reference/user-interface-help/miscellaneous-constants)
[CHAR 関数](https://support.microsoft.com/ja-jp/office/char-%E9%96%A2%E6%95%B0-bbd249c8-b36e-4a91-8017-1c133f9b837a)

# ExcelにJoinで値をいれる。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/126919/5cddcaf3-e3cb-aace-08af-23c976db590b.png)

間が空いている。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/126919/a00ab705-8989-bb1f-b399-9b78b184b114.png)
調べてみるとCの後ろにはスペースのようなものが4つある。
一つは`"C "`だとわかるが、他に3つ存在する。さらに、AとBとCの間も隙間がある。そこで文字をコピーアンドペーストで取り出し下のセルに入力する。


## CHARで空白とわかる

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/126919/35e23362-17e4-1dca-cbca-097d8735447c.png)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/126919/63daa2a2-798c-ff00-ddf6-f791bed2fea7.png)
<font color="RED"><b>驚くべきことに、Null文字は空白'Char(32)`に勝手に変更されている！</b></Font>
つまり、Null文字区切りは半角区切りになってしまったのである。
なので、Cの後ろにスペースが4つあるのは
C空白 区切り空白 空白 区切空白
という並びになっているのである。

## vbNullCharはセルに入らない
それでは`=Char(0)`でセルにvbNullCharは入力できないのか。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/126919/c44b2219-ab6b-a348-5127-8d3c1c4438dc.png)

値のエラーになってしまう。

## 挿入->記号と特殊文字->記号と特殊文字でも入力できない
まず特殊文字の一覧に存在しない。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/126919/d7fb78cf-0541-c427-0165-1fe98a543cf9.png)

制御文字はジャンルとして示されないので、強制的に0000といれて挿入をクリックする。
これを自動記録したマクロで見てみる。

```vb
Sub MacroInsertTest()
' マクロの自動記録で記録
    ActiveCell.FormulaR1C1 = " "
    Range("B1").Select
    ActiveCell.FormulaR1C1 = "=CODE(RC[-1])"
    Range("B2").Select
End Sub
```

このように空白が入力されたことになる。また、Codeの結果は32で半角スペースであることがわかる。

## Char関数は0を使うことができないのでこれでも入力できない
[CHAR 関数](https://support.microsoft.com/ja-jp/office/char-%E9%96%A2%E6%95%B0-bbd249c8-b36e-4a91-8017-1c133f9b837a)

<blockquote>
<h3>説明</h3>
数値で指定された文字を返します。 CHAR 関数は、他機種のコンピューター上にあるファイルから取得したコード ページ番号を文字に変換する場合などに使用します。

 | システム環境 | 文字セット|
 |:-------|:-------------|
 |Macintosh | Macintosh 文字セット|
 |Windows  | <br>ANSI</br><br> ANSI 文字セットは、Windows オペレーティング システムで Windows 95 および Windows NT を通じて使用される標準的な文字セットであり、その後は Unicode が採用されました。 ANSI は 218 文字で構成され、その多くは ASCII/Unicode 形式と同じ数値コードを共有します。 https://www.techopedia.com/definition/932/ansi-character-set</br>|

<h3>書式</h3>
CHAR(数値)
CHAR 関数の書式には、次の引数があります。
    数値    必ず指定します。 変換する文字を表す <b>1</b> ～ 255 の範囲内の数値を指定します。 文字は、コンピューターで使用されている文字セットから返されます。
</blockquote>

<B>とこのように<font color="red">**1**</font>からなのでWorksheetFunction.Char(0)はエラーとなるので、VBAの`Chr(0)`は得ることができない。</b>

## 空白`Chr(32)`は`Chr(0)`で代用できる場合がある
配列を`Chr(0)`で区切ると、セルの中に入れたり、表示させれば空白になる以上、いちいち`Chr(32)`としなくても良いのである。
またイミディエイトに表示させた場合も、同様に空白`Chr(32)`が表示される。
面白いのはこの`null`文字区切りは`Join`等では最終的にスペース区切りと同じになるのにもかかわらず、それまでは空白と別な文字として扱われる。
つまり<b>空白を含む文字列の配列はNull文字区切りで区切るとよい</b>ということになる。
なお、文字数としてはLenの結果を見るとおりゼロではない。半角1字、2バイトを必要とする。

## Trimは無駄無駄無駄無駄アァッ！！！
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/126919/ff8850c7-09a3-b20d-d68d-0d5d92befffd.png)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/126919/5673e7e4-e64d-cfbd-4cbd-46a419315994.png)
`Len(Trim(vbNullChar)) = 1` 
vbNullCharはvbNullStringと異なり、Trimが効かない。
このため、値に混じった空白を除去しても、配列の区切りとしての`Chr(0)`は砕けないのである。

## WorksheetFunction.Cleanは有効
[データをクリーンアップする方法トップ 10](https://support.microsoft.com/ja-jp/office/%E3%83%87%E3%83%BC%E3%82%BF%E3%82%92%E3%82%AF%E3%83%AA%E3%83%BC%E3%83%B3%E3%82%A2%E3%83%83%E3%83%97%E3%81%99%E3%82%8B%E6%96%B9%E6%B3%95%E3%83%88%E3%83%83%E3%83%97-10-2844b620-677c-47a7-ac3e-c2e157d1db19)
CLEAN  7 ビット ASCII コードの先頭から 32 個の印刷されない文字 (値 0 から 31) をテキストから削除します。
Excelを参照設定で持ってくるか、ExcelのVBAにおいてはこの方法も可能だ。ただ、これは32の空白まで削除している。

## 結論 git
in VBA, You can make array with vbNullChar.
But Show On Immidiate Or Cell, vbNullChar change Space Automatically.
VBAでもNull文字区切り配列を作成可能である。
しかし、セル内ではNull文字は勝手に空白に変換される。イミディエイトでも同様である。
ただし、単独でVBAで'Chr(0)`で代入した場合、長さ0の文字列`""`に変換される。

## しかしここでもう一つきがついた
Cleanが`Chr(0)`をのぞけるなら、入力できるのではないか？
そこで`Chr(0)`のみを表示形式を文字列と、標準でやってみた。

```vb
Sub Try_Insert_Char_0()
Dim wb As Workbook: Set wb = ThisWorkbook
Dim ws As Worksheet: Set ws = ActiveSheet
Dim r As Range
Set r = ws.Range(ActiveCell.Address)
r.Clear
Debug.Print "表示形式文字列'chr(0)"
r.NumberFormatLocal = "@"
r.Value = "'" & Chr(0)
Debug.Print "r.Value = Chr(0)  ", r.Value = Chr(0)
Debug.Print "r.Value = Chr(32)  ", r.Value = Chr(32)
Debug.Print "r.Value = vbNullChar", r.Value = vbNullChar
Debug.Print "r.Value = """"", r.Value = ""
Debug.Print "r.Value = vbNullString ", r.Value = vbNullString
Debug.Print "Len(r.Value)  ", Len(r.Value)
Debug.Print "LenB(r.Value)  ", LenB(r.Value)
Debug.Print "StrPtr(r.Value) <> 0 ", StrPtr(r.Value) <> 0
Debug.Print "StrPtr(r.Value)=", StrPtr(r.Value)
r.ClearContents
r.Value = ""
Debug.Print "StrPtr("""")", StrPtr(r.Value)
r.Clear
r.NumberFormatLocal = "@"
Debug.Print "表示形式文字列そのままchr(0)"
r.Value = Chr(0)
Debug.Print "r.Value = Chr(0)  ", r.Value = Chr(0)
Debug.Print "r.Value = Chr(32)  ", r.Value = Chr(32)
Debug.Print "r.Value = vbNullChar", r.Value = vbNullChar
Debug.Print "r.Value = """"", r.Value = ""
Debug.Print "r.Value = vbNullString ", r.Value = vbNullString
Debug.Print "Len(r.Value)  ", Len(r.Value)
Debug.Print "LenB(r.Value)  ", LenB(r.Value)
Debug.Print "StrPtr(r.Value) <> 0 ", StrPtr(r.Value) <> 0
Debug.Print "StrPtr(r.Value)=", StrPtr(r.Value)
r.ClearContents
r.Value = ""
Debug.Print "StrPtr("""")", StrPtr(r.Value)
r.Clear
r.NumberFormatLocal = "G/標準"
Debug.Print "表示形式標準 'chr(0)"
r.Value = "'" & Chr(0)
Debug.Print "r.Value = Chr(0)  ", r.Value = Chr(0)
Debug.Print "r.Value = Chr(32)  ", r.Value = Chr(32)
Debug.Print "r.Value = vbNullChar", r.Value = vbNullChar
Debug.Print "r.Value = """"", r.Value = ""
Debug.Print "r.Value = vbNullString ", r.Value = vbNullString
Debug.Print "Len(r.Value)  ", Len(r.Value)
Debug.Print "LenB(r.Value)  ", LenB(r.Value)
Debug.Print "StrPtr(r.Value) <> 0 ", StrPtr(r.Value) <> 0
Debug.Print "StrPtr(r.Value)=", StrPtr(r.Value)
r.Clear
Debug.Print "StrPtr(r.Value)", StrPtr(r.Value)
r.Value = ""
Debug.Print "StrPtr("""")", StrPtr(r.Value)
r.Clear
r.NumberFormatLocal = "G/標準"
Debug.Print "表示形式文字列そのままchr(0)"
r.Value = Chr(0)
Debug.Print "r.Value = Chr(0)  ", r.Value = Chr(0)
Debug.Print "r.Value = Chr(32)  ", r.Value = Chr(32)
Debug.Print "r.Value = vbNullChar", r.Value = vbNullChar
Debug.Print "r.Value = """"", r.Value = ""
Debug.Print "r.Value = vbNullString ", r.Value = vbNullString
Debug.Print "Len(r.Value)  ", Len(r.Value)
Debug.Print "LenB(r.Value)  ", LenB(r.Value)
Debug.Print "StrPtr(r.Value) <> 0 ", StrPtr(r.Value) <> 0
Debug.Print "StrPtr(r.Value)=", StrPtr(r.Value)
r.Clear
Debug.Print "StrPtr(r.Value)", StrPtr(r.Value)
r.Value = ""
Debug.Print "StrPtr("""")", StrPtr(r.Value)
r.Clear
End Sub
```
## Chr(0)は空文字列`""`に変換された！

https://excel-ubara.com/excelvba4/EXCEL_VBA_421.html

一見vbNullStringのようだが、StrPtrはゼロにならない。
なので長さゼロの文字列`""`に変換されている。
次にならばNullcharを代入する。まずVBAの代入

```vb
Function 長さ0を代入(cnt As Long) As Double
    Dim s As String
    Dim i As Long
    Dim sTime As Double
    sTime = Timer
    For i = 1 To cnt
        s = ""
    Next
    長さ0を代入 = Timer - sTime
End Function
Function NullCharを代入(cnt As Long) As Double
    Dim s As String
    Dim i As Long
    Dim sTime As Double
    sTime = Timer
    For i = 1 To cnt
        s = vbNullChar
    Next
    NullCharを代入 = Timer - sTime
End Function

Function NullStringを代入(cnt As Long) As Double
    Dim s As String
    Dim i As Long
    Dim sTime As Double
    sTime = Timer
    For i = 1 To cnt
        s = vbNullString
    Next
    NullStringを代入 = Timer - sTime
End Function
Sub test()
Debug.Print 長さ0を代入(1000000)
Debug.Print NullCharを代入(1000000)
Debug.Print NullStringを代入(1000000)
End Sub
```

```
 0.3671875 
 0.35546875 
 0.1328125 
```

若干の揺れがあったが、64bitのVBAではNullStringが早い。

### セルをクリアするときはどうか
それでは表示形式、標準ので文字列を`""`、`vbNullChar`、`vbNullStrig`でセルのクリアではどうか

```vb
Function 長さ0を代入(cnt As Long) As Double
    Dim s As String
    Dim i As Long
    Dim sTime As Double
    sTime = Timer
    For i = 1 To cnt
        ActiveCell.Value = ""
    Next
    長さ0を代入 = Timer - sTime
End Function
Function クリアをかける(cnt As Long) As Double
    Dim s As String
    Dim i As Long
    Dim sTime As Double
    sTime = Timer
    For i = 1 To cnt
        ActiveCell.Clear
    Next
    クリアをかける = Timer - sTime
End Function
Function Cクリアをかける(cnt As Long) As Double
    Dim s As String
    Dim i As Long
    Dim sTime As Double
    sTime = Timer
    For i = 1 To cnt
        ActiveCell.Clear
    Next
    Cクリアをかける = Timer - sTime
End Function
Function NullCharを代入(cnt As Long) As Double
    Dim s As String
    Dim i As Long
    Dim sTime As Double
    sTime = Timer
    For i = 1 To cnt
        ActiveCell.Value = vbNullChar
    Next
    NullCharを代入 = Timer - sTime
End Function

Function NullStringを代入(cnt As Long) As Double
    Dim s As String
    Dim i As Long
    Dim sTime As Double
    sTime = Timer
    For i = 1 To cnt
        ActiveCell.Value = vbNullString
    Next
    NullStringを代入 = Timer - sTime
End Function
Sub test()
Debug.Print 長さ0を代入(10)
Debug.Print NullCharを代入(10)
Debug.Print NullStringを代入(10)
Debug.Print クリアをかける(10)
Debug.Print Cクリアをかける(10)
End Sub
```

```
 0.22265625 
 0.15234375 
 0.140625 
 0.14453125 
 0.12109375 

 0.15625 
 0.171875 
 0.140625 
 0.1328125 
 0.125 

 0.1953125 
 0.18359375 
 0.15625 
 0.1328125 
 0.12890625 
```

これは揺れがあるが、ClearContentsが早かった。
長さゼロ、NullChar、NullStrigは平均的には`vbNullString`が最速だが、やはりClearContentsが早いし、わかりやすい。セルの文字列のクリアはCleaContentsを使うべきである。また一度全部消してしまうClearより早いのでその点でもこれを使ったほうが良いと思われる。