【问题标题】:Translate a column index into an Excel Column Name将列索引转换为 Excel 列名
【发布时间】:2010-09-22 18:29:54
【问题描述】:

给定列的索引,如何获得 Excel 列名?

这个问题比听起来更棘手,因为它只是 base-26。这些列不会像普通数字那样环绕。甚至 Microsoft Support Example 也无法扩展到 ZZZ。

免责声明:这是我不久前编写的一些代码,今天它再次出现在我的桌面上。我认为值得将其作为预先回答的问题发布在这里。

【问题讨论】:

标签: .net excel


【解决方案1】:

我想出的答案是有点递归。此代码在 VB.Net 中:

Function ColumnName(ByVal index As Integer) As String
        Static chars() As Char = {"A"c, "B"c, "C"c, "D"c, "E"c, "F"c, "G"c, "H"c, "I"c, "J"c, "K"c, "L"c, "M"c, "N"c, "O"c, "P"c, "Q"c, "R"c, "S"c, "T"c, "U"c, "V"c, "W"c, "X"c, "Y"c, "Z"c}

        index -= 1 ''//adjust so it matches 0-indexed array rather than 1-indexed column

        Dim quotient As Integer = index \ 26 ''//normal / operator rounds. \ does integer division, which truncates
        If quotient > 0 Then
               ColumnName = ColumnName(quotient) & chars(index Mod 26)
        Else
               ColumnName = chars(index Mod 26)
        End If
End Function

在 C# 中:

string ColumnName(int index)
{
    index -= 1; //adjust so it matches 0-indexed array rather than 1-indexed column

    int quotient = index / 26;
    if (quotient > 0)
        return ColumnName(quotient) + chars[index % 26].ToString();
    else
        return chars[index % 26].ToString();
}
private char[] chars = new char[] {'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z'};

唯一的缺点是它使用 1-indexed 列而不是 0-indexed。

【讨论】:

  • +1 不错的解决方案,虽然我更喜欢没有任何字母数组的地方,但这是我在被引导到这个问题之前首先想到的。 =)
  • 您可以使用 (char)(index % 26 + 'A') 代替 char[] 查找
  • 如果将 char 数组更改为字符串数组,您将提高速度,因为您不必从 char 转换为字符串。将您的代码运行到最大 int 并将其与字符串数组进行比较,您会看到不同之处。还有其他一些小事情要添加以使其更快一点。无论以哪种方式运行,它都能完成工作。我只是想我会在这里提到那个小细节。很好的解决方案。
【解决方案2】:

这里是 Joel 的很棒的代码,经过修改,可以使用从零开始的列索引,并且不使用 char 数组。

 Public Shared Function GetExcelColumn(ByVal index As Integer) As String

        Dim quotient As Integer = index \ 26 ''//Truncate 
        If quotient > 0 Then
            Return GetExcelColumn(quotient - 1) & Chr((index Mod 26) + 64).ToString

        Else
            Return Chr(index + 64).ToString

        End If

    End Function

【讨论】:

  • 不应该是+ 65而不是+ 64吗? index Mod 26 的值将在 0 到 25 之间变化。0 + 64@ 字符。
  • 我已将此答案翻译为 python。我将把它作为一个单独的答案发布,以获得漂亮的代码格式。到目前为止,它已经过测试可以达到 GetExcelByColumn(35) = 'AI'
【解决方案3】:

正是出于这个原因,我避免在 Excel 编程界面中使用列名。使用列 numbers 在 Cell(r,c) 引用和 R1C1 寻址中效果很好。

编辑:Range 函数也采用单元格引用,如 Range(Cell(r1,c1),Cell(r2,c2))。此外,您还可以使用 Address 函数获取单元格或区域的 A1 样式地址。

EDIT2:这是一个使用 Address() 函数检索列名的 VBA 函数:

Function colname(colindex)
    x = Cells(1, colindex).Address(False, False) ' get the range name (e.g. AB1)
    colname = Mid(x, 1, Len(x) - 1)              ' return all but last character
End Function

【讨论】:

  • IIRC,您需要 Range() 函数的名称。但我不记得这段代码的原始上下文,所以我无法确定它是如何使用的。
  • +1 我已经尝试过使用它来实现 Range 的 Cell 包装器,效果很好!谢谢!
【解决方案4】:
public static String translateColumnIndexToName(int index) {
        //assert (index >= 0);

        int quotient = (index)/ 26;

        if (quotient > 0) {
            return translateColumnIndexToName(quotient-1) + (char) ((index % 26) + 65);
        } else {
            return "" + (char) ((index % 26) + 65);
        }


    }

和测试:

for (int i = 0; i < 100; i++) {
            System.out.println(i + ": " + translateColumnIndexToName(i));
}

这是输出:

0: A
1: B
2: C
3: D
4: E
5: F
6: G
7: H
8: I
9: J
10: K
11: L
12: M
13: N
14: O
15: P
16: Q
17: R
18: S
19: T
20: U
21: V
22: W
23: X
24: Y
25: Z
26: AA
27: AB
28: AC

我需要 0 基于 POI

以及从索引到名称的翻译:

public static int translateComunNameToIndex0(String columnName) {
        if (columnName == null) {
            return -1;
        }
        columnName = columnName.toUpperCase().trim();

        int colNo = -1;

        switch (columnName.length()) {
            case 1:
                colNo = (int) columnName.charAt(0) - 64;
                break;
            case 2:
                colNo = ((int) columnName.charAt(0) - 64) * 26 + ((int) columnName.charAt(1) - 64);
                break;
            default:
                //illegal argument exception
                throw new IllegalArgumentException(columnName);
        }

        return colNo;
    }

【讨论】:

  • 我尝试了您的代码translateColumnIndexToName 并发现return translateColumnIndexToName(quotient-1) + (char) ((index % 26) + 65); 行导致第一个双字母系列使用VS2010 显示为“@A”、“@B”、“@C”和C# 在一个几乎裸露的控制台应用程序中。这是由递归引起的,当我们再次使用quotient - 1 调用该函数时,由于我在没有-1 的情况下进行了测试,因此它完美无缺。你在没有-1的情况下测试过吗?
【解决方案5】:
# Python 2.x, no recursive function calls

def colname_from_colx(colx):
    assert colx >= 0
    colname = ''
    r = colx
    while 1:
        r, d = divmod(r, 26)
        colname = chr(d + ord('A')) + colname
        if not r:
            return colname
        r -= 1

【讨论】:

    【解决方案6】:

    这是一篇旧帖子,但在看到一些解决方案后,我想出了自己的 C# 变体。从 0 开始,没有递归:

    public static String GetExcelColumnName(int columnIndex)
    {
        if (columnIndex < 0)
        {
            throw new ArgumentOutOfRangeException("columnIndex: " + columnIndex);
        }
        Stack<char> stack = new Stack<char>();
        while (columnIndex >= 0)
        {
            stack.Push((char)('A' + (columnIndex % 26)));
            columnIndex = (columnIndex / 26) - 1;
        }
        return new String(stack.ToArray());
    }
    

    以下是一些关键过渡点的测试结果:

    0: A
    1: B
    2: C
    ...
    24: Y
    25: Z
    26: AA
    27: AB
    ...
    50: AY
    51: AZ
    52: BA
    53: BB
    ...
    700: ZY
    701: ZZ
    702: AAA
    703: AAB
    

    【讨论】:

    • @brettdj - 它标记的问题 .NET(既不是 C# 也不是 VB)。两种语言都有答案。我看不出我的答案不符合条件?
    • 这行得通吗?问题的关键在于它只是一个简单的 % 26。
    • 是的,它确实有效,我同意它并不像看起来那么容易。如果你注意到我除以 26 然后减去 1。我会用测试结果更新我的答案。
    【解决方案7】:

    在python中,带有递归。翻译自Joeyanswer。到目前为止,它已经过测试,可以达到 GetExcelByColumn(35) = 'AI'

    def GetExcelColumn(index):
    
        quotient = int(index / 26)
    
        if quotient > 0:
            return GetExcelColumn(quotient) + str(chr((index % 26) + 64))
    
        else:
            return str(chr(index + 64))
    

    【讨论】:

      【解决方案8】:

      php 版本,感谢这篇文章帮我弄清楚! ^^

      /**
       * Get excel column name
       * @param index : a column index we want to get the value in excel column format
       * @return (string) : excel column format
       */
      function getexcelcolumnname($index) {
          //Get the quotient : if the index superior to base 26 max ?
          $quotient = $index / 26;
          if ($quotient >= 1) {
              //If yes, get top level column + the current column code
              return getexcelcolumnname($quotient-1). chr(($index % 26)+65);
          } else {
              //If no just return the current column code
              return chr(65 + $index);
          }
      }
      

      【讨论】:

        【解决方案9】:

        JavaScript 解决方案

        /**
         * Calculate the column letter abbreviation from a 0 based index
         * @param {Number} value
         * @returns {string}
         */
        getColumnFromIndex = function (value) {
            var base = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'.split('');
            value++;
            var remainder, result = "";
            do {
                remainder = value % 26;
                result = base[(remainder || 26) - 1] + result;
                 value = Math.floor(value / 26);
            } while (value > 0);
            return result;
        };
        

        【讨论】:

          【解决方案10】:

          我喜欢编写递归函数,但我认为这里没有必要。这是我在 VB 中的解决方案。它适用于 ZZ 列。如果有人能告诉我它是否适用于 AAA 到 ZZZ,那就太好了。

          Public Function TranslateColumnIndexToName(index As Integer) As String
          '
          Dim remainder As Integer
          Dim remainder2 As Integer
          Dim quotient As Integer
          Dim quotient2 As Integer
          '
          quotient2 = ((index) / (26 * 26)) - 2
          remainder2 = (index Mod (26 * 26)) - 1
          quotient = ((remainder2) / 26) - 2
          remainder = (index Mod 26) - 1
          '
          If quotient2 > 0 Then
              TranslateColumnIndexToName = ChrW(quotient2 + 65) & ChrW(quotient + 65) & ChrW(remainder + 65)
          ElseIf quotient > 0 Then
              TranslateColumnIndexToName = ChrW(quotient + 65) & ChrW(remainder + 65)
          Else
              TranslateColumnIndexToName = ChrW(remainder + 65)
          End If 
          

          结束函数

          【讨论】:

            【解决方案11】:

            这是我在 C# 中的解决方案

            // test
            void Main()
            {
            
                for( var i = 0; i< 1000; i++ )
                {   var byte_array = code( i );
                    Console.WriteLine("{0} | {1} | {2}", i, byte_array, offset(byte_array));
                }
            }
            
            // Converts an offset to AAA code
            public string code( int offset )
            {
                List<byte> byte_array = new List<byte>();
                while( offset >= 0 )
                {
                    byte_array.Add( Convert.ToByte(65 + offset % 26) );
                    offset = offset / 26 - 1;
                }
                return ASCIIEncoding.ASCII.GetString( byte_array.ToArray().Reverse().ToArray());
            }
            
            // Converts AAA code to an offset
            public int offset( string code)
            {
                var offset = 0;
                var byte_array = Encoding.ASCII.GetBytes( code ).Reverse().ToArray();
                for( var i = 0; i < byte_array.Length; i++ )
                {
                    offset += (byte_array[i] - 65 + 1) * Convert.ToInt32(Math.Pow(26.0, Convert.ToDouble(i)));
                }
                return offset - 1;
            }
            

            【讨论】:

              【解决方案12】:

              这是我在 C# 中的答案,用于在列索引和列名之间进行双向转换。

              /// <summary>
              /// Gets the name of a column given the index, as it would appear in Excel.
              /// </summary>
              /// <param name="columnIndex">The zero-based column index number.</param>
              /// <returns>The name of the column.</returns>
              /// <example>Column 0 = A, 26 = AA.</example>
              public static string GetColumnName(int columnIndex)
              {
                  if (columnIndex < 0) throw new ArgumentOutOfRangeException("columnIndex", "Column index cannot be negative.");
              
                  var dividend = columnIndex + 1;
                  var columnName = string.Empty;
              
                  while (dividend > 0)
                  {
                      var modulo = (dividend - 1) % 26;
                      columnName = Convert.ToChar(65 + modulo) + columnName;
                      dividend = (dividend - modulo) / 26;
                  }
              
                  return columnName;
              }
              
              /// <summary>
              /// Gets the zero-based column index given a column name.
              /// </summary>
              /// <param name="columnName">The column name.</param>
              /// <returns>The index of the column.</returns>
              public static int GetColumnIndex(string columnName)
              {
                  var index = 0;
                  var total = 0;
                  for (var i = columnName.Length - 1; i >= 0; i--)
                      total += (columnName.ToUpperInvariant()[i] - 64) * (int)Math.Pow(26, index++);
              
                  return total - 1;
              }
              

              【讨论】:

                【解决方案13】:

                在 Ruby 中:

                class Fixnum
                  def col_name
                    quot = self/26
                    (quot>0 ? (quot-1).col_name : "") + (self%26+65).chr
                  end
                end
                
                puts 0.col_name # => "A"
                puts 51.col_name # => "AZ"
                

                【讨论】:

                  【解决方案14】:

                  这个 JavaScript 版本表明它的核心是转换为 base 26:

                  function colName(x)
                  {
                      x = (parseInt("ooooooop0", 26) + x).toString(26);
                      return x.slice(x.indexOf('p') + 1).replace(/./g, function(c)
                      {
                          c = c.charCodeAt(0);
                          return String.fromCharCode(c < 64 ? c + 17 : c - 22);
                      });
                  }
                  

                  .toString(26) 位表明 Joel Coehoorn 是错误的:它是一个简单的基础转换。

                  (注意:根据 Dana 在生产中的回答,我有一个更直接的实现。它不那么重,适用于更大的数字,尽管这不会影响我,但也没有清楚地显示数学原理。)

                  附:这是在重要点评估的函数:

                  0 A
                  1 B
                  9 J
                  10 K
                  24 Y
                  25 Z
                  26 AA
                  27 AB
                  700 ZY
                  701 ZZ
                  702 AAA
                  703 AAB
                  18276 ZZY
                  18277 ZZZ
                  18278 AAAA
                  18279 AAAB
                  475252 ZZZY
                  475253 ZZZZ
                  475254 AAAAA
                  475255 AAAAB
                  12356628 ZZZZY
                  12356629 ZZZZZ
                  12356630 AAAAAA
                  12356631 AAAAAB
                  321272404 ZZZZZY
                  321272405 ZZZZZZ
                  321272406 AAAAAAA
                  321272407 AAAAAAB
                  8353082580 ZZZZZZY
                  8353082581 ZZZZZZZ
                  8353082582 AAAAAAAA
                  8353082583 AAAAAAAB
                  

                  【讨论】:

                  • 图像,'A' 是 0 位,B 是 1 位,'Z' 是 9 位。在以 10 为基数的术语中,以 26 为基数的期望是 9、10、11 之类的序列。但是,以 26 为基数的数字映射到 Z、BA、BB 而不是 Z、AA、AB。或者,如果“Z”是数字 0,“A”和“B”是 1 和 2,“Y”是 9,我们会期望 9、10、11。相反,我们会看到 Y、AZ、AA。我并不是说您的 javascript 是错误的:只是您的 javascript 中发生的不仅仅是简单的 base-26 转换。
                  【解决方案15】:

                  这是 Swift 4 :

                  @IBAction func printlaction(_ sender: Any) {
                      let textN : Int = Int (number_textfield.text!)!
                      reslut.text = String (printEXCL_Letter(index: textN))
                  }
                  
                  
                  func printEXCL_Letter(index : Int) -> String {
                  
                      let letters = ["a", "b", "c","d", "e", "f","g", "h", "i","j", "k", "l","m", "n", "o","p", "q", "r","s", "t", "u","v","w" ,"x", "y","z"]
                  
                      var index = index;
                      index -= 1
                      let index_div = index / 26
                  
                      if (index_div > 0){
                          return printEXCL_Letter(index: index_div) + letters[index % 26];
                      }
                      else {
                          return letters[index % 26]
                      }
                  }
                  

                  【讨论】:

                    猜你喜欢
                    • 2014-02-04
                    • 1970-01-01
                    • 2019-05-04
                    • 2012-12-25
                    • 1970-01-01
                    • 1970-01-01
                    • 1970-01-01
                    • 1970-01-01
                    • 2021-12-17
                    相关资源
                    最近更新 更多