VBScript
VBA
VisualBasic

VBAのみで2進数と16進数を互いに変換してみる


始めに

近年のバージョンのExcelには16進数表記を2進数表記に変換するHEX2BIN関数や、2進→16進変換をするBIN2HEX関数がありますが、Accessなどにはないの作ってみました。公開して需要があるのか解りませんが、VB系には汎用性が有ると思うのでメモ替わりに公開してみます。


16進←→2進ってどうやるんだっけ?

コンピューターにおいて二進と十六進の変換は基本中の基本だと思いますが、一応おさらいを。


2進から16進

11010010という数を例にして見ると、まず2進の数を4桁毎に分解します。この場合は1101と0010です。

続いて下の表に従い1の数のところだけ足します。

1
1
0
1

8
4
2
1

0
0
1
0

8
4
2
1

つまり、8+4+1で13です。つぎの2桁は0010なので2です。そうして得られた結果の下の対処表に当てはめれば

11010010の答えがD2であることがわかります。

1
2
3
4
5
6
7
8
9
A
B
C
D
E
F

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15

表1:10進と16進の対照表


16進から2進

今度は逆の操作ですが、一桁ずつ算定していきます。D2の場合はDと2に分解し、以下の表に当てはめましょう。

1
2
3
4
5
6
7
8
9
A
B
C
D
E
F

0001
0010
0011
0100
0101
0110
0111
1000
1001
1010
1011
1100
1101
1110
1111

表2:16進と2進の対照表

Dは1101、2は10なので0010。これを合成すると11010010となります。


実装

16進変換はHEX関数があるのでそれを利用すれば容易にもとめられるのですが、2進にはそんな便利な関数はないので、配列に結果を格納しておいて、11なら「1011を格納したarrBin(11)」を当てはめるというやり方を考えましたし、実際そういう実装をされている方 もいらっしゃったのですが、スマートじゃないのでビット演算で求めることにしました。


解説

どちらともvarBinaryに、若い順番から8,4,2,1を格納し、1(または4)文字取り出し演算を繰り返すシンプルな実装となりました。

varBinaryはVariant型なので念のためCLng関数で変換しています。


16進変換のソースコード


Bin_2_Hex

   Const strBin As String = "11010010"

Dim i As Long
Dim y As Long
Dim lack As Long
Dim tmp As String
Dim lngByte As Long
Dim strAns As String
Dim varBinary As Variant

varBinary = Array("8", "4", "2", "1")

lack = 4 - (Len(strBin) Mod 4)

If lack <> 4 Then
Do Until lack = 0
strBin = "0" & strBin
lack = lack - 1
Loop
End If

For i = 1 To Len(strBin) Step 4

lngByte = 0 '変数の初期化
tmp = Mid(strBin, i, 4) '値を取り出す

For y = 0 To 3
'数を取り出しフラグが立っていると足す
If Mid(tmp, y + 1, 1) = "1" Then
lngByte = lngByte + CLng(varBinary(y))
End If
Next y

strAns = strAns & Hex(lngByte) '答えを格納する
Next i

Debug.Print "答え:" & strAns


追記:最初のコードでは4の倍数ではない数では誤った値が出るので修正しました。


2進変換のソースコード


Hex_2_Bin

    Const strHex As String = "F2"

Dim i As Long
Dim y As Long
Dim tmp As Long
Dim strAns As String
Dim varBinary As Variant

varBinary = Array("8", "4", "2", "1")

For i = 1 To Len(strHex)
tmp = CLng("&h" & Mid(strHex, i, 1)) '値を取り出す

For y = 0 To 3
'数を取り出しフラグが立っていると足す
If (tmp And CLng(varBinary(y))) = 0 Then
strAns = strAns & "0"
Else
strAns = strAns & "1"
End If
Next
Next i

Debug.Print "答え:" & strAns



終わりに

あまりに基礎的なコードであるがゆえにあまりサンプルも載っていなかったこともあり投稿させていただきました。一つでも参考になれれば幸いです。


参考サイト

-2進数 & 10進数 & 16進数 - Part 2 - ネットワークエンジニアとして

-VBAでビット演算(論理演算) - t-hom's diary

-三流君ASP:2進数文字列と16進文字列の変換処理に挑戦


追記

nukie_53さんから


Array関数の引数には、ユーザー定義型以外の大体のものは指定できるため、直接数値を指定してもよいのではないでしょうか?

また、Array関数は、以下のようにOption Baseの影響を受けるためFor y = 0 To 3と決め打ちで書くのはちょっと怖い面があります。

下限が常に0になるVBA.Arrayを使用・・・すると、そのあたりの影響を無視できます。


とあります。試してみたところ、


newcode

'16進に変換

Sub Bin_2_Hex()
Const strBin As String = "11010010"

Dim i As Long
Dim y As Long
Dim tmp As String
Dim lngByte As Long
Dim strAns As String
Dim varBinary As Variant

varBinary = VBA.Array(8&, 4&, 2&, 1&)

For i = 1 To Len(strBin) Step 4

lngByte = 0 '変数の初期化
tmp = Mid(strBin, i, 4) '値を取り出す

For y = 0 To 3
'数を取り出しフラグが立っていると足す
If Mid(tmp, y + 1, 1) = "1" Then
lngByte = lngByte + varBinary(y)
End If
Next y

strAns = strAns & Hex(lngByte) '答えを格納する
Next i

Debug.Print "答え:" & strAns

End Sub

'2進に変換

Sub Hex_2_Bin()
Const strHex As String = "F2"

Dim i As Long
Dim y As Long
Dim tmp As Long
Dim strAns As String
Dim varBinary As Variant

varBinary = VBA.Array(8&, 4&, 2&, 1&)

For i = 1 To Len(strHex)
tmp = CLng("&h" & Mid(strHex, i, 1)) '値を取り出す

For y = 0 To 3
'数を取り出しフラグが立っていると足す
If (tmp And varBinary(y)) = 0 Then
strAns = strAns & "0"
Else
strAns = strAns & "1"
End If
Next
Next i

Debug.Print "答え:" & strAns
End Sub


これでも動作しました。そちらの方がスマートなコードだと思います。ありがとうございました。