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

558

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

Excel 2007的可能范围是1到16384,这是它支持的列数。转换后的值应该是Excel列名的形式,例如A、AA、AAA等。


2
不要忘记可用列数的限制。例如:* Excel 2003(v11)最多到IV,2^8或256列。* Excel 2007(v12)最多到XFD,2^14或16384列。 - Unsliced
1
可能是重复的问题:如何找到对应于给定整数的Excel列名? - Daniel Trebbien
这个问题被标记为C#和Excel。我将此问题标记为过时,因为我们生活在2016年,有EPPLUS。这是一个常用的C#库,可以在服务器上创建高级Excel电子表格。它是根据GNU图书馆通用公共许可证(LGPL)提供的。使用EPPlus,您可以轻松地获取列字符串。 - Tony_KiloPapaMikeGolf
请注意,行和列的限制更多取决于文件格式而不是 Excel 版本,并且对于每个工作簿可能会有所不同。如果将其保存为旧版或新版格式,即使是同一工作簿,它们也可能会发生变化。 - Slai
@Tony_KiloPapaMikeGolf 我认为这并不过时。事实上,EPPLUS已经更改了许可证,这可能不适合各种原因。另外,如果你所需的只是如此简单的东西,为什么要引入一个库呢?我正在使用OpenXML以Excel格式导出数据,只需要一些像这里提问的算法。为什么要混合使用库呢?需求因人而异。该问题并不过时,对于简单的用例仍然很相关。话虽如此,EPPLUS是一个非常酷的库。 ;) - MetalMikester
如果您需要用于Aspose Cells,它们有内置的帮助程序。请参考:https://docs.aspose.com/cells/net/names-and-indices/。 - Uwe Keim
60个回答

1

这是根据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;
};

1

感谢这里的回答!它帮助我编写了一些与 Google Sheets API 交互的辅助函数,我正在使用 Elixir/Phoenix 进行开发。

以下是我编写的代码(可能需要一些额外的验证和错误处理):

Elixir 代码:

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

1

我的解决方案基于GrahamHerman Kandesseim的答案,使用StringBuilder:

internal class Program
{
    #region get_excel_col_name
    /// <summary>
    /// Returns the name of the column by its number
    /// </summary>
    /// <param name="col_num">Column number</param>
    /// <returns>Column name</returns>
    /// <remarks>Numbering columns from zero</remarks>
    private static string get_excel_col_name(int col_num)
    {
        StringBuilder sb = new StringBuilder(2);
        if (col_num >= 0)
        {
            do
            {
                sb.Insert(0, (char)(col_num % 26 + 65));
                col_num /= 26;
            }
            while (--col_num >= 0);
        }
        return sb.ToString();
    }
    #endregion

    private static void Main(string[] args)
    {
        Console.WriteLine(get_excel_col_name(34));//outputs AI
        Console.ReadKey(true);
    }
}

1

这段代码适用于A到ZZ列名

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

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反转它...但看到Graham的答案后,我有点困惑...


Graham说:columnName = Convert.ToChar(65 + modulo).ToString() + columnName(即值+列名)。Hasan说:columnName += val;(即列名+值)。 - mcalex
你正在将新字符附加到末尾,而不是添加到开头。应该是 columnName = val + columnName - Domenic D.

1
这是我的超级迟到的PHP实现。这个是递归的。我在发现这篇文章之前就写了它。我想看看其他人是否已经解决了这个问题...
public function GetColumn($intNumber, $strCol = null) {

    if ($intNumber > 0) {
        $intRem = ($intNumber - 1) % 26;
        $strCol = $this->GetColumn(intval(($intNumber - $intRem) / 26), sprintf('%s%s', chr(65 + $intRem), $strCol));
    }

    return $strCol;
}

1

简洁优雅的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

1

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://dev59.com/QHVC5IYBdhLWcg3wykej#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;
},

感谢 将Excel列字母(例如AA)转换为数字(例如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://dev59.com/Dmkw5IYBdhLWcg3waZ_4
* @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;
}

1
每种方式的 F# 版本。
let rec getExcelColumnName x  = if x<26 then int 'A'+x|>char|>string else (x/26-1|>c)+ c(x%26)

抱歉缩小了,正在制作更好的版本https://dev59.com/6W855IYBdhLWcg3wQx5L#4500043


反方向:

// 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

1
这是其他人和Google都会重定向到的问题,所以我在这里发布它。许多答案是正确的,但对于简单情况(例如您没有超过26列)来说过于繁琐。如果您不确定是否会进入双字符列,则请忽略此答案,但如果您确定不会,则可以在C#中轻松完成此操作:
public static char ColIndexToLetter(short index)
{
    if (index < 0 || index > 25) throw new ArgumentException("Index must be between 0 and 25.");
    return (char)('A' + index);
}

如果您对传入的内容非常自信,甚至可以删除验证并使用以下内联代码:
(char)('A' + index)

这在许多语言中都非常相似,因此您可以根据需要进行调整。
同样,仅当您确定不会超过26列时才使用此方法

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接