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

Excel 从列索引获取单元地址列字母和从列字母获取列索引的最佳方法,excel,vba,indexing,letter,Excel,Vba,Indexing,Letter,通常,公认的方法是执行以下操作 数字与字母 字母对数字 但是,这两种方法都不是特别理想的,因为在每种情况下,我们都要创建一个对象,然后对该对象调用属性访问器。有更快的方法吗?总结 要认识到的核心是Excel中使用的字母系统也被称为Base26NumberToLetter从十进制编码到Base26,而letttonumber从Base26解码到十进制 基本转换可以通过简单的循环和 Function base26Encode(ByVal iDecimal As Long) As String i

通常,公认的方法是执行以下操作

数字与字母 字母对数字 但是,这两种方法都不是特别理想的,因为在每种情况下,我们都要创建一个对象,然后对该对象调用属性访问器。有更快的方法吗?

总结 要认识到的核心是Excel中使用的字母系统也被称为Base26
NumberToLetter
从十进制编码到Base26,而
letttonumber
从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
结果如下:

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倍)。但是,我很惊讶对象创建和属性访问的表现如此出色。

您没有创建对象-在这两种情况下,单元格都已经存在。如果您确实需要在列字母和索引之间进行映射,那么这对我来说似乎很好:如果您尝试映射不存在的列,那么它将出错。@TimWilliams我非常确定
范围(…)
amd
单元格(…)
将创建一个对象,或者更确切地说,我很确定,没有为您打开的每个电子表格创建一些
2147483647
对象(整个电子表格中的每个单元格一个对象),因为这会非常慢。好吧,公平点…而不是
v=iDecimal Mod 26
&
如果v=0,那么v=26
使用
v=(iDecimal-1)Mod 26+1
速度相当但代码更清晰。此外,如果您将0传递到函数中,您会得到一个奇怪的字符串,因此对此进行错误检查是很好的。
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