从列索引中获取单元格地址列字母和从列字母中获取列索引的最佳方法

Optimal means of obtaining cell address column letter from column index and column index from column letter

通常接受的方法是执行以下操作

数字到字母

public function numberToLetter(ByVal i as long) as string
  Dim s as string: s = cells(1,i).address(false,false)
  numberToLetter = left(s,len(s)-1)
end function

给数字的信

Public Function letterToNumber(ByVal s As String) As Long
  letterToNumber = Range(s & 1).Column
End Function

然而,这些都不是特别理想的,因为在每种情况下我们都创建一个对象,然后在该对象上调用 属性 访问器。有没有更快的方法?

总结

要实现的核心是 Excel 中使用的字母系统也称为 Base26。 NumberToLetter是从十进制编码到Base26,LetterToNumber是从Base26解码到十进制。

基本转换可以通过简单的循环和

完成
Function base26Encode(ByVal iDecimal As Long) As String
  if iDecimal <= 0 then Call Err.Raise(5, "base26Encode" ,"Argument cannot be less than 0")
  if iDecimal >= 16384 then Call Err.Raise(5, "base26Encode" ,"There are only 16384 columns in a spreadsheet, thus this function is limited to this number.")
  Dim s As String: s = ""
  Do
    Dim v As Long
    v = (iDecimal - 1) Mod 26 + 1
    iDecimal = (iDecimal - v) / 26
    s = Chr(v + 64) & s
  Loop Until iDecimal = 0
  base26Encode = s
End Function

Function base26Decode(ByVal sBase26 As String) As Long
  sBase26 = UCase(sBase26)
  Dim sum As Long: sum = 0
  Dim iRefLen As Long: iRefLen = Len(sBase26)
  For i = iRefLen To 1 Step -1
    sum = sum + (Asc((Mid(sBase26, i))) - 64) * 26 ^ (iRefLen - i)
  Next
  base26Decode = sum
End Function

性能

我针对原始函数测试了这些函数的性能。为此,我使用了 stdVBA 的 stdPerformance class。

用于测试的代码如下:

Sub testPerf()
  Dim cMax As Long: cMax = 16384
  With stdPerformance.Measure("Encode Original")
    For i = 1 To cMax
      Call numberToLetter(i)
    Next
  End With
  With stdPerformance.Measure("Encode Optimal")
    For i = 1 To cMax
      Call base26Encode(i)
    Next
  End With
  With stdPerformance.Measure("Decode Original")
    For i = 1 To cMax
      Call letterToNumber(base26Encode(i))
    Next
  End With
  With stdPerformance.Measure("Decode Optimal")
    For i = 1 To cMax
      Call base26Decode(base26Encode(i))
    Next
  End With
End Sub

其中的结果如下:

Encode Original: 78 ms
Encode Optimal: 31 ms
Decode Original: 172 ms
Decode Optimal: 63 ms

如图所示,这是一种稍快的方法(快 2-3 倍)。然而,对象创建和 属性 访问执行得如此之好,我感到相当惊讶。