【问题标题】:How to convert a column number (e.g. 127) into an Excel column (e.g. AA)如何将列号(例如 127)转换为 Excel 列(例如 AA)
【发布时间】:2008-10-08 06:55:01
【问题描述】:

如何在 C# 中将数字转换为 Excel 列名,而不使用直接从 Excel 中自动获取值。

Excel 2007 的可能范围为 1 到 16384,这是它支持的列数。结果值应采用 excel 列名的形式,例如A、AA、AAA等。

【问题讨论】:

  • 不要忘记可用列的数量是有限制的。例如。 * Excel 2003 (v11) 达到 IV、2^8 或 256 列)。 * Excel 2007 (v12) 增加到 XFD、2^14 或 16384 列。
  • 这个问题被标记为 C# 和 excel。我将此问题标记为已过时,因为我们生活在 2016 年并且有 EPPLUS。一个常用的 C# 库,用于在服务器上创建高级 Excel 电子表格。可通过以下方式获得:GNU 库通用公共许可证 (LGPL)。使用 EPPlus 可以轻松获取 Column 字符串。
  • 请注意,与 Excel 版本相比,行和列限制更多地取决于文件格式,并且每个工作簿可能不同。如果将同一工作簿保存为较旧或较新的格式,它们甚至可以更改。
  • @Tony_KiloPapaMikeGolf 我不认为这已经过时了。事实上,EPPLUS 已经改变了他们的许可,由于各种原因,这可能并不适合所有人。另外,如果你只需要这么简单的东西,为什么还要带一个图书馆呢?我正在使用 OpenXML 以 Excel 格式导出数据,我只需要几个算法,就像这里所要求的那样。为什么要添加一个库?需求不同。这个问题并没有过时,并且与简单的用例相关。也就是说,EPPLUS 是一个非常酷的库。 ;)

标签: c# excel


【解决方案1】:

我正在尝试在 Java 中做同样的事情... 我写了以下代码:

private String getExcelColumnName(int columnNumber) {

    int dividend = columnNumber;
    String columnName = "";
    int modulo;

    while (dividend > 0)
    {
        modulo = (dividend - 1) % 26;

        char val = Character.valueOf((char)(65 + modulo));

        columnName += val;

        dividend = (int)((dividend - modulo) / 26);
    } 

    return columnName;
}

现在,一旦我使用 columnNumber = 29 运行它,它就会给我结果 =“CA”(而不是“AC”) 有什么我想念的吗? 我知道我可以通过 StringBuilder 扭转它....但是看着格雷厄姆的回答,我有点困惑....

【讨论】:

  • 格雷厄姆说:columnName = Convert.ToChar(65 + modulo).ToString() + columnName(即值 + ColName)。哈桑说:columnName += val;(即 ColName + 值)
  • 您是在附加新字符而不是在其前面。应该是columnName = columnName + val
【解决方案2】:

简洁优雅的Ruby版本:

def col_name(col_idx)
    name = ""
    while col_idx>0
        mod     = (col_idx-1)%26
        name    = (65+mod).chr + name
        col_idx = ((col_idx-mod)/26).to_i
    end
    name
end

【讨论】:

    【解决方案3】:

    NodeJS 实现:

    /**
    * getColumnFromIndex
    * Helper that returns a column value (A-XFD) for an index value (integer).
    * The column follows the Common Spreadsheet Format e.g., A, AA, AAA.
    * See https://stackoverflow.com/questions/181596/how-to-convert-a-column-number-eg-127-into-an-excel-column-eg-aa/3444285#3444285
    * @param numVal: Integer
    * @return String
    */
    getColumnFromIndex: function(numVal){
       var dividend = parseInt(numVal);
       var columnName = '';
       var modulo;
       while (dividend > 0) {
          modulo = (dividend - 1) % 26;
          columnName = String.fromCharCode(65 + modulo) + columnName;
          dividend = parseInt((dividend - modulo) / 26);
       }
       return columnName;
    },
    

    感谢Convert excel column alphabet (e.g. AA) to number (e.g., 25)。反过来:

    /**
    * getIndexFromColumn
    * Helper that returns an index value (integer) for a column value (A-XFD).
    * The column follows the Common Spreadsheet Format e.g., A, AA, AAA.
    * See https://stackoverflow.com/questions/9905533/convert-excel-column-alphabet-e-g-aa-to-number-e-g-25
    * @param strVal: String
    * @return Integer
    */
    getIndexFromColumn: function(val){
       var base = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ', i, j, result = 0;
       for (i = 0, j = val.length - 1; i < val.length; i += 1, j -= 1) {
          result += Math.pow(base.length, j) * (base.indexOf(val[i]) + 1);
       }
       return result;
    }
    

    【讨论】:

      【解决方案4】:

      每种方式的F#版本

      let rec getExcelColumnName x  = if x<26 then int 'A'+x|>char|>string else (x/26-1|>c)+ c(x%26)
      

      请原谅最小化,正在开发更好的https://stackoverflow.com/a/4500043/57883版本


      和相反的方向:
      // return values start at 0
      let getIndexFromExcelColumnName (x:string) =
          let a = int 'A'
          let fPow len i =
              Math.Pow(26., len - 1 - i |> float)
              |> int
      
          let getValue len i c = 
              int c - a + 1 * fPow len i
          let f i = getValue x.Length i x.[i]
          [0 .. x.Length - 1]
          |> Seq.map f
          |> Seq.sum
          |> fun x -> x - 1
      

      【讨论】:

        【解决方案5】:

        在这里感谢您的回答!帮助我想出了这些帮助函数,以便与我在 Elixir/Phoenix 中使用的 Google Sheets API 进行一些交互

        这是我想出的(可能会使用一些额外的验证和错误处理)

        在灵药中:

        def number_to_column(number) do
          cond do
            (number > 0 && number <= 26) ->
              to_string([(number + 64)])
            (number > 26) ->
              div_col = number_to_column(div(number - 1, 26))
              remainder = rem(number, 26)
              rem_col = cond do
                (remainder == 0) ->
                  number_to_column(26)
                true ->
                  number_to_column(remainder)
              end
              div_col <> rem_col
            true ->
              ""
          end
        end
        

        还有反函数:

        def column_to_number(column) do
          column
            |> to_charlist
            |> Enum.reverse
            |> Enum.with_index
            |> Enum.reduce(0, fn({char, idx}, acc) ->
              ((char - 64) * :math.pow(26,idx)) + acc
            end)
            |> round
        end
        

        还有一些测试:

        describe "test excel functions" do
          @excelTestData [{"A", 1}, {"Z",26}, {"AA", 27}, {"AB", 28}, {"AZ", 52},{"BA", 53}, {"AAA", 703}]
        
          test "column to number" do
            Enum.each(@excelTestData, fn({input, expected_result}) ->
              actual_result = BulkOnboardingController.column_to_number(input)
              assert actual_result == expected_result
            end)
          end
        
          test "number to column" do
            Enum.each(@excelTestData, fn({expected_result, input}) ->
              actual_result = BulkOnboardingController.number_to_column(input)
              assert actual_result == expected_result
            end)
          end
        end
        

        【讨论】:

          【解决方案6】:

          这是根据 Graham 的代码编写的 javascript 版本

          function (columnNumber) {
              var dividend = columnNumber;
              var columnName = "";
              var modulo;
          
              while (dividend > 0) {
                  modulo = (dividend - 1) % 26;
                  columnName = String.fromCharCode(65 + modulo) + columnName;
                  dividend = parseInt((dividend - modulo) / 26);
              }
          
              return columnName;
          };
          

          【讨论】:

            【解决方案7】:

            之前的大部分答案都是正确的。这是将列号转换为 excel 列的另一种方法。 如果我们将此视为基本转换,则解决方案相当简单。只需将列号转换为基数 26,因为只有 26 个字母。 以下是您可以执行此操作的方法:

            步骤:

            • 将列设置为商

            • 从商变量中减去一个(来自上一步),因为我们需要以 ascii table 结束,其中 97 是 a。

            • 除以 26 得到余数。

            • 将 +97 添加到余数并转换为 char(因为 97 在 ASCII 表中是“a”)
            • 商成为新的商/26(因为我们可能会超过 26 列)
            • 继续这样做,直到商大于0,然后返回结果

            这是执行此操作的代码:)

            def convert_num_to_column(column_num):
                result = ""
                quotient = column_num
                remainder = 0
                while (quotient >0):
                    quotient = quotient -1
                    remainder = quotient%26
                    result = chr(int(remainder)+97)+result
                    quotient = int(quotient/26)
                return result
            
            print("--",convert_num_to_column(1).upper())
            

            【讨论】:

              【解决方案8】:

              此 sn-p 适用于 A 到 ZZ 列名称

              string columnName = columnNumber > 26 ? Convert.ToChar(64 + (columnNumber / 26)).ToString() + Convert.ToChar(64 + (columnNumber % 26)) : Convert.ToChar(64 + columnNumber).ToString();
              

              【讨论】:

                【解决方案9】:

                我在 VB.NET 2003 中使用这个,它运行良好...

                Private Function GetExcelColumnName(ByVal aiColNumber As Integer) As String
                    Dim BaseValue As Integer = Convert.ToInt32(("A").Chars(0)) - 1
                    Dim lsReturn As String = String.Empty
                
                    If (aiColNumber > 26) Then
                        lsReturn = GetExcelColumnName(Convert.ToInt32((Format(aiColNumber / 26, "0.0").Split("."))(0)))
                    End If
                
                    GetExcelColumnName = lsReturn + Convert.ToChar(BaseValue + (aiColNumber Mod 26))
                End Function
                

                【讨论】:

                  【解决方案10】:

                  另一种解决方案:

                  private void Foo()
                  {
                     l_ExcelApp = new Excel.ApplicationClass();
                     l_ExcelApp.ReferenceStyle = Excel.XlReferenceStyle.xlR1C1;
                     // ... now reference by R[row]C[column], Ex. A1 <==> R1C1, C6 <==> R3C6, ...
                  }
                  

                  在此处查看更多信息 - Cell referencing in Excel for everyone! by Dr Nitin Paranjape

                  【讨论】:

                  • ApplicationClass 类型自 Excel 2003 以来一直不可行。停止使用错误的编码。
                  【解决方案11】:
                  public static string ConvertToAlphaColumnReferenceFromInteger(int columnReference)
                      {
                          int baseValue = ((int)('A')) - 1 ;
                          string lsReturn = String.Empty; 
                  
                          if (columnReference > 26) 
                          {
                              lsReturn = ConvertToAlphaColumnReferenceFromInteger(Convert.ToInt32(Convert.ToDouble(columnReference / 26).ToString().Split('.')[0]));
                          } 
                  
                          return lsReturn + Convert.ToChar(baseValue + (columnReference % 26));            
                      }
                  

                  【讨论】:

                  • 你能补充一些解释吗?
                  【解决方案12】:

                  在 VB.Net 2005 中使用它:

                  Private Function ColumnName(ByVal ColumnIndex As Integer) As String
                  
                     Dim Name As String = ""
                  
                     Name = (New Microsoft.Office.Interop.Owc11.Spreadsheet).Columns.Item(ColumnIndex).Address(False, False, Microsoft.Office.Interop.Owc11.XlReferenceStyle.xlA1)
                     Name = Split(Name, ":")(0)
                  
                     Return Name
                  
                  End Function
                  

                  【讨论】:

                  • 好主意。但糟糕的表现明智。隐式地新建一个对象,然后使用另外四个点来调用最终的 Address 方法将导致一些可怕的互操作编组。肯定需要重写。
                  【解决方案13】:

                  如果您想以编程方式引用单元格,那么如果您使用工作表的 Cells 方法,您将获得更具可读性的代码。它采用行和列索引而不是传统的单元格引用。与 Offset 方法非常相似。

                  【讨论】:

                  • ?单元格可能是在 Excel 中引用范围的最糟糕的方式。它的表现令人震惊。偏移或只是 Worksheet.Range 会好得多。
                  【解决方案14】:

                  这是我在 Python 中的做法。算法解释如下:

                  alph = ('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')
                  def labelrec(n, res):
                      if n<26:
                          return alph[n]+res
                      else:
                          rem = n%26
                          res = alph[rem]+res
                          n = n/26-1
                          return labelrec(n, res)
                  

                  函数 labelrec 可以用数字和空字符串调用,例如:

                  print labelrec(16383, '')
                  

                  这就是它起作用的原因: 如果十进制数的写入方式与 Excel 工作表的列相同,则数字 0-9 将正常写入,但 10 将变为“00”,然后 20 将变为“10”,依此类推。映射几个数字:

                  0 - 0

                  9 - 9

                  10 - 00

                  20 - 10

                  100 - 90

                  110 - 000

                  1110 - 0000

                  所以,模式很清楚。从单位开始,如果一个数字小于 10,它的表示与数字本身相同,否则您需要通过将剩余的数字减去 1 并递归来调整剩余的数字。当数量小于 10 时可以停止。

                  同样的逻辑适用于上述解决方案中以 26 为底的数字。

                  附:如果您希望数字从 1 开始,请在将输入数字减 1 后调用相同的函数。

                  【讨论】:

                    【解决方案15】:

                    (我意识到这个问题与 C# 有关,但是如果有人阅读需要使用 Java 做同样的事情,那么以下内容可能会有用)

                    事实证明,这可以使用Jakarta POI 中的“CellReference”类轻松完成。此外,转换可以通过两种方式完成。

                    // Convert row and column numbers (0-based) to an Excel cell reference
                    CellReference numbers = new CellReference(3, 28);
                    System.out.println(numbers.formatAsString());
                    
                    // Convert an Excel cell reference back into digits
                    CellReference reference = new CellReference("AC4");
                    System.out.println(reference.getRow() + ", " + reference.getCol());
                    

                    【讨论】:

                      【解决方案16】:

                      我今天刚要做这个工作,我的实现使用递归:

                      private static string GetColumnLetter(string colNumber)
                      {
                          if (string.IsNullOrEmpty(colNumber))
                          {
                              throw new ArgumentNullException(colNumber);
                          }
                      
                          string colName = String.Empty;
                      
                          try
                          {
                              var colNum = Convert.ToInt32(colNumber);
                              var mod = colNum % 26;
                              var div = Math.Floor((double)(colNum)/26);
                              colName = ((div > 0) ? GetColumnLetter((div - 1).ToString()) : String.Empty) + Convert.ToChar(mod + 65);
                          }
                          finally
                          {
                              colName = colName == String.Empty ? "A" : colName;
                          }
                      
                          return colName;
                      }
                      

                      这将数字作为字符串的方法和以“0”开头的数字(A = 0)

                      【讨论】:

                        【解决方案17】:

                        Objective-C 实现:

                        -(NSString*)getColumnName:(int)n {
                             NSString *name = @"";
                             while (n>0) {
                             n--;
                             char c = (char)('A' + n%26);
                             name = [NSString stringWithFormat:@"%c%@",c,name];
                             n = n/26;
                          }    
                             return name;
                        

                        }

                        SWIFT 实施:

                        func getColumnName(n:Int)->String{
                         var columnName = ""
                         var index = n
                         while index>0 {
                             index--
                             let char = Character(UnicodeScalar(65 + index%26))
                             columnName = "\(char)\(columnName)"
                             index = index / 26
                         }
                         return columnName
                        

                        }

                        答案基于:https://stackoverflow.com/a/4532562/2231118

                        【讨论】:

                          【解决方案18】:

                          打字稿

                          function lengthToExcelColumn(len: number): string {
                          
                              let dividend: number = len;
                              let columnName: string = '';
                              let modulo: number = 0;
                          
                              while (dividend > 0) {
                                  modulo = (dividend - 1) % 26;
                                  columnName = String.fromCharCode(65 + modulo).toString() + columnName;
                                  dividend = Math.floor((dividend - modulo) / 26);
                              }
                              return columnName;
                          }
                          

                          【讨论】:

                            【解决方案19】:

                            似乎很多答案比必要的复杂得多。这是基于上述递归的通用 Ruby 答案:

                            这个答案的一个好处是它不限于英文字母的 26 个字符。您可以在COLUMNS 常量中定义您喜欢的任何范围,它会做正确的事情。

                              # vim: ft=ruby
                              class Numeric
                                COLUMNS = ('A'..'Z').to_a
                            
                                def to_excel_column(n = self)
                                  n < 1 ?  '' : begin
                                    base = COLUMNS.size
                                    to_excel_column((n - 1) / base) + COLUMNS[(n - 1) % base]
                                  end
                                end
                              end
                            
                              # verify:
                              (1..52).each { |i| printf "%4d => %4s\n", i, i.to_excel_column }
                            

                            这会打印以下内容,例如:

                               1 =>    A
                               2 =>    B
                               3 =>    C
                              ....
                              33 =>   AG
                              34 =>   AH
                              35 =>   AI
                              36 =>   AJ
                              37 =>   AK
                              38 =>   AL
                              39 =>   AM
                              40 =>   AN
                              41 =>   AO
                              42 =>   AP
                              43 =>   AQ
                              44 =>   AR
                              45 =>   AS
                              46 =>   AT
                              47 =>   AU
                              48 =>   AV
                              49 =>   AW
                              50 =>   AX
                              51 =>   AY
                              52 =>   AZ
                            

                            【讨论】:

                              【解决方案20】:

                              这是编码测试中常见的问题。 它有一些限制: 每行最大列数= 702 输出应该有行号+列名,例如703 的答案是 2A。 (注意:我刚刚从另一个答案修改了现有代码) 这是相同的代码:

                                  static string GetExcelColumnName(long columnNumber)
                                  {
                                      //max number of column per row
                                      const long maxColPerRow = 702;
                                      //find row number
                                      long rowNum = (columnNumber / maxColPerRow);
                                      //find tierable columns in the row.
                                      long dividend = columnNumber - (maxColPerRow * rowNum);
                              
                                      string columnName = String.Empty;
                              
                                      long modulo;
                              
                                      while (dividend > 0)
                                      {
                                          modulo = (dividend - 1) % 26;
                                          columnName = Convert.ToChar(65 + modulo).ToString() + columnName;
                                          dividend = (int)((dividend - modulo) / 26);
                                      }
                              
                                      return rowNum+1+ columnName;
                                  }
                              }
                              

                              【讨论】:

                                【解决方案21】:

                                T-SQL (SQL SERVER 18)

                                第一页解决方案的副本

                                CREATE FUNCTION dbo.getExcelColumnNameByOrdinal(@RowNum int)  
                                RETURNS varchar(5)   
                                AS   
                                BEGIN  
                                    DECLARE @dividend int = @RowNum;
                                    DECLARE @columnName varchar(max) = '';
                                    DECLARE @modulo int;
                                
                                    WHILE (@dividend > 0)
                                    BEGIN  
                                        SELECT @modulo = ((@dividend - 1) % 26);
                                        SELECT @columnName = CHAR((65 + @modulo)) + @columnName;
                                        SELECT @dividend = CAST(((@dividend - @modulo) / 26) as int);
                                    END
                                    RETURN 
                                       @columnName;
                                
                                END;
                                

                                【讨论】:

                                  【解决方案22】:

                                  这是一个基于零的列索引的更简单解决方案

                                   public static string GetColumnIndexNumberToExcelColumn(int columnIndex)
                                          {
                                              int offset = columnIndex % 26;
                                              int multiple = columnIndex / 26;
                                  
                                              int initialSeed = 65;//Represents column "A"
                                              if (multiple == 0)
                                              {
                                                  return Convert.ToChar(initialSeed + offset).ToString();
                                              }
                                  
                                              return $"{Convert.ToChar(initialSeed + multiple - 1)}{Convert.ToChar(initialSeed + offset)}";
                                          }
                                  

                                  【讨论】:

                                    【解决方案23】:

                                    看到另一个 VBA 答案 - 这可以在 中使用 1 行 UDF 完成:

                                    Function GetColLetter(ByVal colID As Integer) As String
                                        If colID > Columns.Count Then
                                            Err.Raise 9, , "Column index out of bounds"
                                        Else
                                            GetColLetter = Split(Cells(1, colID).Address, "$")(1)
                                        End If
                                    End Function
                                    

                                    【讨论】:

                                    • 超级。这是@paulma 的变体
                                    【解决方案24】:

                                    Microsoft Excel Miniature,速成公式。

                                    嗨,

                                    这是从数字中获取 Excel 字符列标题的一种方法......

                                    我为 Excel 单元格创建了一个公式。

                                    (即我采取了不使用VBA编程的方法。)

                                    该公式查看一个包含数字的单元格,并告诉您该列是什么——用字母表示。

                                    在附图中:

                                    • 我将 1、2、3 等放在顶行一直到 ABS 列。
                                    • 我将公式一直粘贴到第二行,一直到 ABS。
                                    • 我的公式查看第 1 行并将数字转换为 Excel 的列标题 ID。
                                    • 我的公式适用于 702 (zz) 以内的所有数字。
                                    • 我这样做是为了证明公式有效,因此您可以查看公式的输出并查看上面的列标题,并轻松直观地验证公式是否有效。 :-)

                                      =CONCATENATE(MID("_abcdefghijklmnopqrstuvwxyz",(IF(MOD(K1,26)>0,INT(K1/26)+1,(INT(K1/26)))),1),MID(" abcdefghijklmnopqrstuvwxyz",IF(MOD(K1,26)=0,26,MOD(K1,26)),1))

                                    下划线用于调试目的 - 让您知道有一个实际空间并且它工作正常。

                                    使用上面的这个公式——无论你在 K1 中输入什么——这个公式都会告诉你列标题是什么。

                                    当前形式的公式仅包含 2 位数字 (ZZ),但可以修改为添加第三个字母 (ZZZ)。

                                    【讨论】:

                                      【解决方案25】:

                                      这是我在 python 中的解决方案

                                      import math
                                      
                                      num = 3500
                                      row_number = str(math.ceil(num / 702))
                                      letters = ''
                                      num = num - 702 * math.floor(num / 702)
                                      while num:
                                          mod = (num - 1) % 26
                                          letters += chr(mod + 65)
                                          num = (num - 1) // 26
                                      result = row_number + ("".join(reversed(letters)))
                                      print(result)
                                      
                                      

                                      【讨论】:

                                        【解决方案26】:
                                            public string ToBase26(int number)
                                            {
                                                if (number < 0) return String.Empty;
                                        
                                                int remainder = number % 26;
                                                int value = number / 26;
                                        
                                                return value == 0 ?
                                                    String.Format("{0}", Convert.ToChar(65 + remainder)) :
                                                    String.Format("{0}{1}", ToBase26(value - 1), Convert.ToChar(65 + remainder));
                                            }
                                        

                                        【讨论】:

                                        • 这不仅仅是一个简单的 base-26 转换。阅读其他答案。
                                        • 假设第一列是 0。0 将返回 A,26​​ 将返回 AA,702 将返回 AAA。我的和第一个正确答案的不同之处在于,它以 1 开头,而我的以 0 开头。这就是我的理解。如果我错了,请纠正我。
                                        • @dirn 你错了。以 10 为底数到 26,将 11 转换为 A,而不是 1 到 A。
                                        猜你喜欢
                                        • 2012-04-11
                                        • 2012-03-23
                                        • 2018-05-26
                                        • 1970-01-01
                                        • 2010-10-18
                                        • 2012-12-25
                                        相关资源
                                        最近更新 更多