如何将列号(例如 127)转换为 Excel 列(例如 AA)

Posted

技术标签:

【中文标题】如何将列号(例如 127)转换为 Excel 列(例如 AA)【英文标题】:How to convert a column number (e.g. 127) into an Excel column (e.g. 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 列。 How do I find the Excel column name that corresponds to a given integer?的可能重复 这个问题被标记为 C# 和 excel。我将此问题标记为已过时,因为我们生活在 2016 年并且有 EPPLUS。一个常用的 C# 库,用于在服务器上创建高级 Excel 电子表格。可通过以下方式获得:GNU 库通用公共许可证 (LGPL)。使用 EPPlus 可以轻松获取 Column 字符串。 请注意,与 Excel 版本相比,行和列限制更多地取决于文件格式,并且每个工作簿可能不同。如果将同一工作簿保存为较旧或较新的格式,它们甚至可以更改。 @Tony_KiloPapaMikeGolf 我不认为这已经过时了。事实上,EPPLUS 已经改变了他们的许可,由于各种原因,这可能并不适合所有人。另外,如果你只需要这么简单的东西,为什么还要带一个图书馆呢?我正在使用 OpenXML 以 Excel 格式导出数据,我只需要几个算法,就像这里所要求的那样。为什么要添加一个库?需求不同。这个问题并没有过时,并且与简单的用例相关。也就是说,EPPLUS 是一个非常酷的库。 ;) 【参考方案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://***.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://***.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://***.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://***.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 答案 - 这可以在 excel-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("01", 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。

以上是关于如何将列号(例如 127)转换为 Excel 列(例如 AA)的主要内容,如果未能解决你的问题,请参考以下文章

EXCEL如何编写宏,将列变量为A的字符型数字,自动转换为数值型并替代原单元值?

如何在不丢失科学记数法的情况下将列转换为单个管道分隔的列?

MySQL将列转换为行

Pandas:将列转换为唯一列表

如何在不知道 NA 值模式的情况下快速将列转换为数字

使用R将行转换为列,将列转换为行