一、背景
1、在EXCEL表格中,将十六进制转换为十进制的常用方法是:使用HEX2DEC函数。
2、在EXCEL的一个单元格中,如果输入形如"12E36"之类的可以被成功识别为“科学计数法”的文本,EXCEL就会自动将该单元格中的文本以“科学计数法”的方式进行解释转换。这种智能转换的初衷本是为了提供帮助,但如果"12E36"本身其实是一个十六进制数时,这种转换则会给用户添加不少麻烦。
二、策略
鉴于以上原因,我在EXCEL中显示和处理十六进制数时,倾向于在原始的十六进制文本前面加上"0x"前缀。以这种方式表示十六进制数,既有助于人为直观判断,又能抑制EXCEL不适当的智能转换。
三、转换方法
在这里,我总结了自己使用HEX2DEC函数,将含有"0x"前缀的十六进制数转换为十进制数的三种方法。
前两种方法都采用VBA宏实现,都会用到相同的自定义函数HexToDec(其中用到了Hex2Dec函数)。代码如下:
Function HexToDec(cell)
Dim hexStr As String
Dim hexVal As String
Dim decVal As String
hexStr = cell.Value
hexVal = Right(hexStr, Len(hexStr) - 2) ' 去掉"0x"前缀(即头两个字符),得到真正代表十六进制值的文本
On Error Resume Next ' 开启错误处理开关(因为文本内容不一定都满足十六进制格式,所以HEX2DEC函数转换时可能会出错)
decVal = Application.WorksheetFunction.Hex2Dec(hexVal) ' 十六进制 --> 十进制
If Err.Number = 0 Then '转换未出错
cell.Value = decVal
If cell.Value = "0" Then ' 将转换为十进制后值为0的单元格的字体变灰,以便区分
cell.Font.Color = RGB(200, 200, 200)
End If
End If
On Error GoTo 0 ' 关闭错误处理开关(在函数结尾处,可以忽略)
End Function
1、在活动工作表被选中的单元格区域中,遍历各个单元格;依次判断每个单元格的值,如果是以"0x"为前缀的,则借助于HexToDec函数进行转换。代码如下:
Sub ConvertData_1()
Dim rowCount As Long
Dim columnCount As Long
Dim row As Long
Dim column As Long
Dim cell As Object
rowCount = Application.Selection.Rows.Count ' 得到被选中单元格区域中包含的行数
columnCount = Application.Selection.Columns.Count ' 得到被选中单元格区域中包含的列数
With Application.Selection
For row = 1 To rowCount
For column = 1 To columnCount
Set cell = .Cells(row, column)
If Left(cell.Value, 2) = "0x" Then ' 如果单元格的值以"0x"为前缀
HexToDec cell ' 将该单元格的值从十六进制转换为十进制
End If
Next column
Next row
End With
End Sub
2、在活动工作表被选中的单元格区域中,使用Range对象的Find方法逐个查找以"0x"为前缀的单元格;如果查找到满足条件的单元格,则借助于HexToDec函数对其值进行转换。代码如下:
Sub ConvertData_2()
Dim cell As Object
With Application.Selection
Set cell = .Find("0x", LookIn:=xlValues) ' 查找以"0x"为前缀的单元格
If Not cell Is Nothing Then ' 如果查找成功
firstAddress = cell.Address
Do
HexToDec Cells(cell.row, cell.column)
Set cell = .FindNext(cell)
On Error Resume Next ' 开启错误处理开关
' 查找并转换完毕所有满足条件的单元格后,执行下面这行语句应该条件为假从而跳出循环;
' 但不知为何,实际情况是:此时会出错,所以特别增加了错误处理
Loop While Not cell Is Nothing And cell.Address <> firstAddress
If Err.Number <> 0 Then ' 如果出错,表明已经查找并转换完毕,退出
Exit Sub
End If
On Error GoTo 0 ' 关闭错误处理开关(在函数结尾处,可以忽略)
End If
End With
End Sub
3、直接在EXCEL表格中为含有十六进制数据的单元格指定Formula属性:使用转换公式(配合Hex2Dec函数、Right函数和Len函数),然后使用Copy方法拷贝相同的公式到其他含有十六进制数据的单元格中。转换公式如下:
=HEX2DEC(RIGHT(A1, LEN(A1) - 2)) ' 针对A1单元格的转换公式
四、比较
1、方法1、2采用VBA宏编写,更为灵活:
(1)对于不满足十六进制格式的文本数据,可以跳过不处理,进而做到只转换满足格式的数据,不满足格式的数据不会受影响。
(2)可以根据转换后数值的不同,设置单元格的属性(如将值为0的单元格的字体变灰)。
2、方法1与方法2相比,方法2的速度更快,可能是得益于“Find方法”的查找效率高于“人为过滤”的效率。
3、相比方法1、2而言,方法3的速度是最快的(而且要快得多),批量转换效率极高。但不足的地方有:
(1)由于是直接写在EXCEL表中的,不如VBA宏编程来得灵活;
(2)转换后得到的十进制数据一般出现在新的单元格中,所以属于拷贝转换,而不是替换;
(3)Copy方法往往针对大块连续的单元格区域,其中若含有不满足十六进制格式的数据,也会一并被转换,不但转换后的数据是无效的,之前的原始数据也受到了影响(没有被保留)。
当然如果能够保证所有待转换的数据都满足十六进制格式(即以"0x"为前缀,并且后续字符均代表有效的十六进制数字),并且待转换的数据量非常大,那么使用方法3将会是最佳的选择。