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

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


当前回答

下面是我在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后调用相同的函数。

其他回答

我的解决方案基于Graham, Herman Kan和desseim的回答,使用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);
    }
}

JavaScript解决方案

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

这是编程测试中常见的问题。 它有一些约束条件: 每行最大列数= 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;
    }
}

谢谢你的回答!!帮助我想出了这些帮助函数,与我正在Elixir/Phoenix中工作的谷歌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

这是所有其他人以及谷歌重定向到的问题,所以我在这里发布这个。

这些答案中有许多是正确的,但对于简单的情况来说太麻烦了,比如当您的列不超过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)

这在许多语言中是非常相似的,因此您可以根据需要进行调整。

同样,只有在100%确定不超过26列的情况下才使用这种方法。