Как преобразовать номер столбца (например, 127) в столбец Excel (например, AA)

Как преобразовать числовое число в имя столбца Excel на C# без использования автоматизации, получая значение непосредственно из Excel.

Excel 2007 имеет возможный диапазон от 1 до 16384, т.е. количество поддерживаемых столбцов. Результирующие значения должны быть в форме имен столбцов Excel, например A, AA, AAA и т. д.

Не забывая, что есть ограничения на количество доступных столбцов. Например. * Excel 2003 (v11) доходит до IV, 2 ^ 8 или 256 столбцов). * Excel 2007 (v12) может содержать до XFD, 2 ^ 14 или 16384 столбца.

Unsliced 08.10.2008 12:34

Этот вопрос помечен как C# и Excel. Я помечаю этот вопрос как устаревший, потому что мы живем в 2016 году и есть EPPLUS. Часто используемая библиотека C# для создания расширенных электронных таблиц Excel на сервере. Это доступно по лицензии GNU Library General Public License (LGPL). Используя EPPlus, вы можете легко получить строку столбца.

Tony_KiloPapaMikeGolf 14.12.2016 12:42

Обратите внимание, что ограничения строк и столбцов больше зависят от формата файла, чем от версии Excel, и могут быть разными для каждой книги. Они могут измениться даже для одной и той же книги, если она сохранена в более старом или новом формате.

Slai 14.12.2016 22:45

@Tony_KiloPapaMikeGolf Я не думаю, что это устарело. Фактически, EPPLUS изменили свое лицензирование, которое может не подходить всем по разным причинам. Кроме того, зачем приносить библиотеку, если все, что вам нужно, настолько простое? Я экспортирую данные в формате Excel с помощью OpenXML, и мне понадобилось всего несколько алгоритмов, подобных тому, о котором здесь спрашивают. Зачем добавлять в микс библиотеку? Потребности меняются. Вопрос не устарел и актуален для простых случаев использования. Тем не менее, EPPLUS - довольно классная библиотека. ;)

MetalMikester 22.06.2020 16:07

Если вам это нужно для ячеек Aspose, у них есть встроенные помощники.

Uwe Keim 16.09.2020 10:58
Стоит ли изучать PHP в 2026-2027 годах?
Стоит ли изучать PHP в 2026-2027 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
491
6
246 460
55
Перейти к ответу Данный вопрос помечен как решенный

Ответы 55

int nCol = 127;
string sChars = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
string sCol = "";
while (nCol >= 26)
{
    int nChar = nCol % 26;
    nCol = (nCol - nChar) / 26;
    // You could do some trick with using nChar as offset from 'A', but I am lazy to do it right now.
    sCol = sChars[nChar] + sCol;
}
sCol = sChars[nCol] + sCol;

Обновлять: Комментарий Питер правильный. Вот что я получаю за написание кода в браузере. :-) Мое решение не компилировалось, в нем отсутствовала крайняя левая буква, и оно строило строку в обратном порядке - теперь все исправлено.

Помимо ошибок, алгоритм в основном преобразует число из основания 10 в основание 26.

Обновление 2: Джоэл Кохорн верен - приведенный выше код вернет AB для 27. Если бы это было действительное число с основанием 26, AA было бы равно A, а следующее число после Z было бы BA.

int nCol = 127;
string sChars = "0ABCDEFGHIJKLMNOPQRSTUVWXYZ";
string sCol = "";
while (nCol > 26)
{
    int nChar = nCol % 26;
    if (nChar == 0)
        nChar = 26;
    nCol = (nCol - nChar) / 26;
    sCol = sChars[nChar] + sCol;
}
if (nCol != 0)
    sCol = sChars[nCol] + sCol;

Код не компилируется (sCol не инициализирован). Если это так, он не даст правильного ответа.

Peter 08.10.2008 13:05

ЭТОТ ОТВЕТ НЕПРАВИЛЬНЫЙ. Base26 недостаточно хорош. Подумайте, что произойдет, если вы перейдете от Z к AA. Если A эквивалентно цифре 0, то это похоже на перенос от 9 до 00. Если это цифры 1, это похоже на перенос от 9 до 11.

Joel Coehoorn 22.11.2008 00:41

Я не понимаю после обновлений ... правильный ли какой-либо из алгоритмов? И если да, то какой, второй? Я бы отредактировал это и сделаю очевидным для потомков ...

JoeCool 27.07.2009 23:51

Легко с рекурсией.

public static string GetStandardExcelColumnName(int columnNumberOneBased)
{
  int baseValue = Convert.ToInt32('A');
  int columnNumberZeroBased = columnNumberOneBased - 1;

  string ret = "";

  if (columnNumberOneBased > 26)
  {
    ret = GetStandardExcelColumnName(columnNumberZeroBased / 26) ;
  }

  return ret + Convert.ToChar(baseValue + (columnNumberZeroBased % 26) );
}

.. или петлю. Здесь нет реальной причины использовать рекурсию.

Blorgbeard 08.10.2008 14:15

Это не просто база 26, поэтому рекурсивное решение намного проще.

Joel Coehoorn 22.11.2008 00:33

Эта процедура на самом деле не работает. Например, GetStandardExcelColumnName (26) возвращает @ GetStandardExcelColumnName (52) возвращает B @

sgmoore 10.03.2010 23:01

самое ясное, а не «простое» решение - лучшее.

Anonymous Type 23.07.2010 03:21

Извините, это Python вместо C#, но, по крайней мере, результаты верны:

def ColIdxToXlName(idx):
    if idx < 1:
        raise ValueError("Index is too small")
    result = ""
    while True:
        if idx > 26:
            idx, r = divmod(idx - 1, 26)
            result = chr(r + ord('A')) + result
        else:
            return chr(idx + ord('A') - 1) + result


for i in xrange(1, 1024):
    print "%4d : %s" % (i, ColIdxToXlName(i))

Да, я проголосовал против, не публикуйте Python, когда вопрос касается C#. И да, больше людей должны это делать.

KyloRen 21.07.2019 12:31

Название вопроса не подразумевает C#, поэтому сюда может прийти много людей, которые не исключают C#. Следовательно, спасибо за то, что поделились Python!

Tim-Erwin 16.09.2019 11:35
Ответ принят как подходящий

Вот как я это делаю:

private string GetExcelColumnName(int columnNumber)
{
    int dividend = columnNumber;
    string columnName = String.Empty;
    int modulo;

    while (dividend > 0)
    {
        modulo = (dividend - 1) % 26;
        columnName = Convert.ToChar(65 + modulo).ToString() + columnName;
        dividend = (int)((dividend - modulo) / 26);
    } 

    return columnName;
}

Этот код работает хорошо. Предполагается, что столбец A - это номер столбца 1. Мне пришлось быстро внести изменения, чтобы учесть мою систему, используя столбец А как номер столбца 0. Я изменил строку int dividnd на int dividnd = columnNumber + 1; Кит

Keith Sirmons 06.08.2009 22:33

Вероятно, вы могли бы сделать это немного быстрее, удалив конкатенации строк и используя StringBuilder. Я работаю с OpenXML, поэтому мне нужна максимальная скорость. +1 хотя, это правильно.

Jduv 04.05.2011 21:08

@Jduv только что попробовал использовать StringBuilder. На это уходит примерно вдвое больше времени. Это очень короткая строка (максимум 3 символа - Excel 2010 идет до столбца XFD), поэтому не более двух конкатенаций строк. (В качестве теста я использовал 100 итераций перевода целых чисел от 1 до 16384, то есть столбцов A Excel в XFD).

Graham 04.05.2011 23:06

Для лучшего понимания я бы заменил 65 на «А».

Stef Heyenrath 11.11.2011 15:12

Собираюсь написать это сам, рад, что проверил, это более элегантно, чем то, о чем я думал.

TravisWhidden 27.12.2012 01:23

Я думаю, было бы лучше использовать «A» вместо 65. И 26 можно было бы оценить как («Z» - «A» + 1), например: const int AlphabetLength = «Z» - «A» + 1;

Denis Gladkiy 03.11.2013 10:14

@Graham Я только что попробовал StringBuilder - он всего на ~ 1,2 медленнее, чем конкатенация строк (не в 2 раза). Но все равно медленнее струны.

Denis Gladkiy 03.11.2013 10:28

Почему вы ЕЩЕ ЕЩЕ используете ДРУГОЙ переменный (дивиденд), выделенный в стеке? Используйте сам параметр (columnNumber) ... Это не ссылка и не указатель, поэтому его совершенно безопасно использовать - и он работает так же быстро, как и еще одна локальная переменная. PS: параметры - это локальные переменные ...

ZioBit 13.06.2016 11:30

Хотя я опаздываю в игру, код далек от оптимального, в частности, вам не нужно использовать modulo, вызывать ToString() и применять приведение (int). Учитывая, что в большинстве случаев в мире C# вы начинаете нумерацию с 0, вот моя редакция: <! - language: C# -> public static string GetColumnName (int index) // с нуля {const byte BASE = 'Z '-' А '+ 1; имя строки = String.Empty; сделать {имя = Convert.ToChar ('A' + индекс% BASE) + имя; index = index / BASE - 1; } while (индекс> = 0); возвращаемое имя; }

Herman Kan 18.08.2016 15:23

@HermanKan, как мне изменить его, чтобы он не начинался с нуля. Столбцы Excel не отсчитываются от нуля, они начинаются с 1. В противном случае это бесполезно.

Leo Gurdian 28.11.2016 21:56

@LeoGurdian, это довольно просто: ... GetColumnName(int col) { int index = col - 1; ...

Herman Kan 29.11.2016 08:31

Не знаю, как он был выбран как правильный ответ. Поскольку для меня это не подходит для базового тестового примера: он дает AZ, когда я прохожу 26. Правильный ответ - Z. Пожалуйста, поправьте меня, если я что-то упускаю.

Kiran 29.12.2016 16:22

Привет @ Грэм, не так ли? Я скопировал этот фрагмент и выполнил его без каких-либо изменений в C#, но я не получил Z в качестве ответа, когда ввел 26. Это как-то связано с языком?

Kiran 30.12.2016 08:22

Привет @bill, я снова забыл ответить. Показанный здесь фрагмент действительно сработал для меня. Я допустил ошибку при копировании. Сообщите мне, если у вас возникнут проблемы.

Kiran 12.07.2017 11:56

Понятно. Кажется, что Dividnd = (int) ((Dividend - modulo-1) / 26) тоже подойдет?

bill 13.07.2017 01:57

@HermanKan: Надеюсь, вы провели несколько тестов производительности, которые ясно показывают, что modulo неоптимален по сравнению с .ToString()? XD

quetzalcoatl 05.05.2020 19:32

private String getColumn(int c) {
    String s = "";
    do {
        s = (char)('A' + (c % 26)) + s;
        c /= 26;
    } while (c-- > 0);
    return s;
}

Это не совсем база 26, в системе нет 0. Если бы это было так, за «Z» следовало бы «BA», а не «AA».

Я использую его в 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

Если вы хотите ссылаться на ячейку программно, вы получите гораздо более читаемый код, если будете использовать метод Cells листа. Он принимает индекс строки и столбца вместо традиционной ссылки на ячейку. Он очень похож на метод смещения.

? Ячейки - это, возможно, худший способ ссылаться на диапазон в Excel. Его производительность просто ужасна. Offset или просто Worksheet.Range намного лучше.

Anonymous Type 23.07.2010 03:27

Если кому-то нужно сделать это в Excel без VBA, вот способ:

=SUBSTITUTE(ADDRESS(1;colNum;4);"1";"")

где colNum - номер столбца

И в VBA:

Function GetColumnName(colNum As Integer) As String
    Dim d As Integer
    Dim m As Integer
    Dim name As String
    d = colNum
    name = ""
    Do While (d > 0)
        m = (d - 1) Mod 26
        name = Chr(65 + m) + name
        d = Int((d - m) / 26)
    Loop
    GetColumnName = name
End Function

Пример: = ПОДСТАВИТЬ (ТЕКСТ (АДРЕС (1,1000,4), ""), "1", "")

Dolph 13.10.2010 22:55

Да, я использую Excel в стране, где; используется вместо, для разделения аргументов функции в Excel. Спасибо за указание на это.

vzczc 14.10.2010 11:05

Я сделал это без функции ТЕКСТ. Какова цель функции ТЕКСТ?

dayuloli 28.01.2014 22:49

@dayuloli Давненько с тех пор, как был написан этот ответ, вы правы, функция ТЕКСТ здесь не служит цели. Обновлю ответ.

vzczc 29.01.2014 13:03

Используя это в 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

хорошая идея. но ужасная производительность. неявное создание объекта с последующим использованием еще четырех точек для вызова метода final Address приведет к ужасному маршаллингу взаимодействия. однозначно нужно переписать.

Anonymous Type 23.07.2010 03:28

Уточнение исходного решения (на C#):

public static class ExcelHelper
{
    private static Dictionary<UInt16, String> l_DictionaryOfColumns;

    public static ExcelHelper() {
        l_DictionaryOfColumns = new Dictionary<ushort, string>(256);
    }

    public static String GetExcelColumnName(UInt16 l_Column)
    {
        UInt16 l_ColumnCopy = l_Column;
        String l_Chars = "0ABCDEFGHIJKLMNOPQRSTUVWXYZ";
        String l_rVal = "";
        UInt16 l_Char;


        if (l_DictionaryOfColumns.ContainsKey(l_Column) == true)
        {
            l_rVal = l_DictionaryOfColumns[l_Column];
        }
        else
        {
            while (l_ColumnCopy > 26)
            {
                l_Char = l_ColumnCopy % 26;
                if (l_Char == 0)
                    l_Char = 26;

                l_ColumnCopy = (l_ColumnCopy - l_Char) / 26;
                l_rVal = l_Chars[l_Char] + l_rVal;
            }
            if (l_ColumnCopy != 0)
                l_rVal = l_Chars[l_ColumnCopy] + l_rVal;

            l_DictionaryOfColumns.ContainsKey(l_Column) = l_rVal;
        }

        return l_rVal;
    }
}

Другое решение:

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, ...
}

подробнее здесь - Ссылка на ячейки в Excel для всех! Доктор Нитин Паранджапе

Тип ApplicationClass не использовался со времен Excel 2003. Прекратите использовать плохое кодирование.

Anonymous Type 23.07.2010 03:25

..И преобразовал в php:

function GetExcelColumnName($columnNumber) {
    $columnName = '';
    while ($columnNumber > 0) {
        $modulo = ($columnNumber - 1) % 26;
        $columnName = chr(65 + $modulo) . $columnName;
        $columnNumber = (int)(($columnNumber - $modulo) / 26);
    }
    return $columnName;
}

Используйте ord('A') вместо 65.

Mulli 07.07.2019 17:25

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));            
    }

Не могли бы вы добавить какие-нибудь пояснения?

jeremy 27.12.2012 14:33

Вот версия ActionScript:

private var columnNumbers:Array = ['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'];

    private function getExcelColumnName(columnNumber:int) : String{
        var dividend:int = columnNumber;
        var columnName:String = "";
        var modulo:int;

        while (dividend > 0)
        {
            modulo = (dividend - 1) % 26;
            columnName = columnNumbers[modulo] + columnName;
            dividend = int((dividend - modulo) / 26);
        } 

        return columnName;
    }

Вам может потребоваться преобразование в обоих направлениях, например, из адреса столбца Excel, такого как AAZ, в целое число и из любого целого числа в Excel. Два нижеприведенных метода сделают это. Предполагается, что индексирование на основе 1, первым элементом в ваших «массивах» является элемент номер 1. Здесь нет ограничений по размеру, поэтому вы можете использовать такие адреса, как ERROR, и это будет номер столбца 2613824 ...

public static string ColumnAdress(int col)
{
  if (col <= 26) { 
    return Convert.ToChar(col + 64).ToString();
  }
  int div = col / 26;
  int mod = col % 26;
  if (mod == 0) {mod = 26;div--;}
  return ColumnAdress(div) + ColumnAdress(mod);
}

public static int ColumnNumber(string colAdress)
{
  int[] digits = new int[colAdress.Length];
  for (int i = 0; i < colAdress.Length; ++i)
  {
    digits[i] = Convert.ToInt32(colAdress[i]) - 64;
  }
  int mul=1;int res=0;
  for (int pos = digits.Length - 1; pos >= 0; --pos)
  {
    res += digits[pos] * mul;
    mul *= 26;
  }
  return res;
}

Я обнаружил ошибку в своем первом посте, поэтому решил сесть и посчитать. Я обнаружил, что система счисления, используемая для идентификации столбцов Excel, не является системой с основанием 26, как писал другой человек. Рассмотрим следующее в базе 10. Вы также можете сделать это с буквами алфавита.

Пространство: ......................... S1, S2, S3: S1, S2, S3
.................................... 0, 00, 000: .. A, AA, AAA
.................................... 1, 01, 001: .. B, AB, AAB
....................................…,…,…: ..…,…,…
.................................... 9, 99, 999: .. Z, ZZ, ZZZ
Всего состояний в пространстве: 10, 100, 1000: 26, 676, 17576
Всего состояний: ............... 1110 ................ 18278

Excel нумерует столбцы в отдельных алфавитных пространствах, используя базу 26. Вы можете видеть, что в целом прогрессия пространства состояний равна a, a ^ 2, a ^ 3,… для некоторой базы a, а общее количество состояний равно a + a ^ 2 + а ^ 3 +….

Предположим, вы хотите найти общее количество состояний A в первых N пробелах. Формула для этого: A = (a) (a ^ N - 1) / (a-1). Это важно, потому что нам нужно найти пространство N, которое соответствует нашему индексу K. Если я хочу выяснить, где находится K в системе счисления, мне нужно заменить A на K и решить для N. Решение: N = log { основание a} (A (a-1) / a +1). Если я использую пример a = 10 и K = 192, я знаю, что N = 2,23804…. Это говорит мне, что K находится в начале третьего промежутка, так как он немного больше двух.

Следующим шагом будет определение того, как далеко мы находимся в текущем пространстве. Чтобы найти это, вычтите из K значение A, полученное с использованием минимального значения N. В этом примере минимальное значение N равно двум. Итак, A = (10) (10 ^ 2-1) / (10-1) = 110, как и ожидалось, когда вы объединяете состояния первых двух пробелов. Это необходимо вычесть из K, потому что эти первые 110 состояний уже были учтены в первых двух пространствах. Остается 82 государства. Итак, в этой системе счисления 192 в базе 10 представлены как 082.

Код C# с нулевым базовым индексом:

    private string ExcelColumnIndexToName(int Index)
    {
        string range = string.Empty;
        if (Index < 0 ) return range;
        int a = 26;
        int x = (int)Math.Floor(Math.Log((Index) * (a - 1) / a + 1, a));
        Index -= (int)(Math.Pow(a, x) - 1) * a / (a - 1);
        for (int i = x+1; Index + i > 0; i--)
        {
            range = ((char)(65 + Index % a)).ToString() + range;
            Index /= a;
        }
        return range;
    }

// Старый пост

Решение с отсчетом от нуля на C#.

    private string ExcelColumnIndexToName(int Index)
    {
        string range = "";
        if (Index < 0 ) return range;
        for(int i=1;Index + i > 0;i=0)
        {
            range = ((char)(65 + Index % 26)).ToString() + range;
            Index /= 26;
        }
        if (range.Length > 1) range = ((char)((int)range[0] - 1)).ToString() + range.Substring(1);
        return range;
    }

ох, я не знаю почему, но мне нравится это решение. Ничего особенного, просто хорошее использование логики ... легко читаемый код для уровней программиста. Однако я считаю, что лучше всего указывать пустую строку в C# как string range = string.Empty;

Anonymous Type 10.08.2010 02:15

Да, очень красивое объяснение. Но не могли бы вы также просто заявить, что это тоже не база 27? Ваше объяснение показывает это при изучении, но быстрое упоминание вверху может сэкономить время некоторым другим людям.

Marius 02.09.2013 23:57

если вам просто нужна формула ячейки без кода, вот формула для нее:

IF(COLUMN()>=26,CHAR(ROUND(COLUMN()/26,1)+64)&CHAR(MOD(COLUMN(),26)+64),CHAR(COLUMN()+64))

    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));
    }

Это не просто преобразование по основанию 26. Прочтите другие ответы.

Joel Coehoorn 15.11.2010 23:00

Предполагая, что первый столбец равен 0. 0 вернет A, 26 вернет AA, а 702 вернет AAA. Разница между моим и первым правильным ответом заключалась в том, что он начинался с 1, а мой - с 0. Это мое понимание. Поправьте меня если я ошибаюсь.

dirn 18.11.2010 10:20

@dirn ты ошибаешься. База с 10 до 26 преобразует 11 в A, а не 1 в A.

Benubird 20.08.2013 19:22

Такая же реализация на Java

public String getExcelColumnName (int columnNumber) 
    {     
        int dividend = columnNumber;   
        int i;
        String columnName = "";     
        int modulo;     
        while (dividend > 0)     
        {        
            modulo = (dividend - 1) % 26;         
            i = 65 + modulo;
            columnName = new Character((char)i).toString() + columnName;        
            dividend = (int)((dividend - modulo) / 26);    
        }       
        return columnName; 
    }  

В Delphi (Паскаль):

function GetExcelColumnName(columnNumber: integer): string;
var
  dividend, modulo: integer;
begin
  Result := '';
  dividend := columnNumber;
  while dividend > 0 do begin
    modulo := (dividend - 1) mod 26;
    Result := Chr(65 + modulo) + Result;
    dividend := (dividend - modulo) div 26;
  end;
end;

Вот как я бы сделал это на 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 в приведенном выше решении.

P.S. Если вы хотите, чтобы числа начинались с 1, вызовите ту же функцию для номера ввода, уменьшив его на 1.

Посмотрев на все представленные здесь версии, я решил сделать одну самостоятельно, используя рекурсию.

Вот моя версия vb.net:

Function CL(ByVal x As Integer) As String
    If x >= 1 And x <= 26 Then
        CL = Chr(x + 64)
    Else
        CL = CL((x - x Mod 26) / 26) & Chr((x Mod 26) + 1 + 64)
    End If
End Function

Немного поздно в игре, но вот код, который я использую (на C#):

private static readonly string _Alphabet = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
public static int ColumnNameParse(string value)
{
    // assumes value.Length is [1,3]
    // assumes value is uppercase
    var digits = value.PadLeft(3).Select(x => _Alphabet.IndexOf(x));
    return digits.Aggregate(0, (current, index) => (current * 26) + (index + 1));
}

Вы сделали обратное тому, о чем просили, но +1 для вашего лямбда-фу.

nurettin 28.02.2012 16:00

IndexOf довольно медленный, лучше просчитать обратное отображение.

Vlad 25.05.2012 12:48

Я пытаюсь сделать то же самое на 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 + значение)

mcalex 28.03.2013 09:51

Вы добавляете новый символ вместо его добавления. Должен быть columnName = columnName + val.

Domenic D. 24.01.2020 21:32

В perl для входа 1 (A), 27 (AA) и т. д.

sub excel_colname {
  my ($idx) = @_;       # one-based column number
  --$idx;               # zero-based column index
  my $name = "";
  while ($idx >= 0) {
    $name .= chr(ord("A") + ($idx % 26));
    $idx   = int($idx / 26) - 1;
  }
  return scalar reverse $name;
}

Я удивлен, что все решения пока содержат либо итерацию, либо рекурсию.

Вот мое решение, которое работает в постоянное время (без циклов). Это решение работает для всех возможных столбцов Excel и проверяет, можно ли преобразовать ввод в столбец Excel. Возможные столбцы находятся в диапазоне [A, XFD] или [1, 16384]. (Это зависит от вашей версии Excel)

private static string Turn(uint col)
{
    if (col < 1 || col > 16384) //Excel columns are one-based (one = 'A')
        throw new ArgumentException("col must be >= 1 and <= 16384");

    if (col <= 26) //one character
        return ((char)(col + 'A' - 1)).ToString();

    else if (col <= 702) //two characters
    {
        char firstChar = (char)((int)((col - 1) / 26) + 'A' - 1);
        char secondChar = (char)(col % 26 + 'A' - 1);

        if (secondChar == '@') //Excel is one-based, but modulo operations are zero-based
            secondChar = 'Z'; //convert one-based to zero-based

        return string.Format("{0}{1}", firstChar, secondChar);
    }

    else //three characters
    {
        char firstChar = (char)((int)((col - 1) / 702) + 'A' - 1);
        char secondChar = (char)((col - 1) / 26 % 26 + 'A' - 1);
        char thirdChar = (char)(col % 26 + 'A' - 1);

        if (thirdChar == '@') //Excel is one-based, but modulo operations are zero-based
            thirdChar = 'Z'; //convert one-based to zero-based

        return string.Format("{0}{1}{2}", firstChar, secondChar, thirdChar);
    }
}

К вашему сведению: ответ @ Graham (и, вероятно, другие) более общий, чем ваш: они поддерживают 4+ символа в именах столбцов. И именно поэтому они итеративны.

bernard paulus 10.07.2013 18:25

Фактически, если бы они использовали неограниченное количество целых чисел, а не int, результирующее имя столбца могло бы быть произвольно длинным (например, в случае ответа python)

bernard paulus 10.07.2013 18:25

Если мои данные окажутся слишком большими для таблицы с 16 384 столбцами, я выстрелю себе в голову. В любом случае, Excel даже не поддерживает все возможные трехбуквенные столбцы (он обрезается в XFD, оставляя 1894 столбца). Во всяком случае, прямо сейчас. Я буду обновлять свой ответ в будущем по мере необходимости.

user2023861 10.07.2013 18:45

:) не знал этого! Мой комментарий касался теоретических свойств различных алгоритмов.

bernard paulus 10.07.2013 19:17

Это, наверное, самое простое и понятное решение.

Juan 11.07.2018 09:24

Слишком сложно. Циклы - это законный способ сделать код коротким и читаемым.

Mulli 07.07.2019 16:50

+1 для отображения максимальной ссылки на ячейку - вы не поверите, как сложно найти эту информацию в Интернете.

controlbox 15.12.2019 18:43

@controlbox вот совет. Откройте новую таблицу Excel и щелкните любую ячейку. Затем, удерживая нажатой клавишу Control, щелкните стрелку вправо. Он перейдет в столбец XFD. Если вместо этого щелкнуть стрелку вниз (удерживая нажатой клавишу), вы перейдете к строке 1048576. Это быстрый способ найти максимальную ссылку на ячейку.

user2023861 17.12.2019 17:10

Этот ответ находится в javaScript:

function getCharFromNumber(columnNumber){
    var dividend = columnNumber;
    var columnName = "";
    var modulo;

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

Вот моя супер поздняя реализация на 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;
}

Решение 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;
};

Попробуйте индекс 26 и 27. Он очень близок, но отстает на единицу.

Eric 11.07.2015 00:12

значение = Math.floor (значение / 26); должно быть значение = Math.ceil (value / 26) - 1;

Henry Liu 12.04.2019 12:49

(Я понимаю, что вопрос относится к C#, однако, если кому-то нужно сделать то же самое с Ява, тогда может быть полезно следующее)

Оказывается, это легко сделать с помощью класса CellReference в Джакарта POI. Кроме того, преобразование может быть выполнено в обоих направлениях.

// 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());

Другой способ VBA

Public Function GetColumnName(TargetCell As Range) As String
    GetColumnName = Split(CStr(TargetCell.Cells(1, 1).Address), "$")(1)
End Function

Я хотел добавить свой статический класс, который я использую, для взаимодействия между индексом столбца и меткой столбца. Я использую измененный принятый ответ для своего метода ColumnLabel

public static class Extensions
{
    public static string ColumnLabel(this int col)
    {
        var dividend = col;
        var columnLabel = string.Empty;
        int modulo;

        while (dividend > 0)
        {
            modulo = (dividend - 1) % 26;
            columnLabel = Convert.ToChar(65 + modulo).ToString() + columnLabel;
            dividend = (int)((dividend - modulo) / 26);
        } 

        return columnLabel;
    }
    public static int ColumnIndex(this string colLabel)
    {
        // "AD" (1 * 26^1) + (4 * 26^0) ...
        var colIndex = 0;
        for(int ind = 0, pow = colLabel.Count()-1; ind < colLabel.Count(); ++ind, --pow)
        {
            var cVal = Convert.ToInt32(colLabel[ind]) - 64; //col A is index 1
            colIndex += cVal * ((int)Math.Pow(26, pow));
        }
        return colIndex;
    }
}

Используйте это как ...

30.ColumnLabel(); // "AD"
"AD".ColumnIndex(); // 30

Эти мои коды для преобразования определенного числа (начало индекса с 1) в столбец Excel.

    public static string NumberToExcelColumn(uint number)
    {
        uint originalNumber = number;

        uint numChars = 1;
        while (Math.Pow(26, numChars) < number)
        {
            numChars++;

            if (Math.Pow(26, numChars) + 26 >= number)
            {
                break;
            }               
        }

        string toRet = "";
        uint lastValue = 0;

        do
        {
            number -= lastValue;

            double powerVal = Math.Pow(26, numChars - 1);
            byte thisCharIdx = (byte)Math.Truncate((columnNumber - 1) / powerVal);
            lastValue = (int)powerVal * thisCharIdx;

            if (numChars - 2 >= 0)
            {
                double powerVal_next = Math.Pow(26, numChars - 2);
                byte thisCharIdx_next = (byte)Math.Truncate((columnNumber - lastValue - 1) / powerVal_next);
                int lastValue_next = (int)Math.Pow(26, numChars - 2) * thisCharIdx_next;

                if (thisCharIdx_next == 0 && lastValue_next == 0 && powerVal_next == 26)
                {
                    thisCharIdx--;
                    lastValue = (int)powerVal * thisCharIdx;
                }
            }

            toRet += (char)((byte)'A' + thisCharIdx + ((numChars > 1) ? -1 : 0));

            numChars--;
        } while (numChars > 0);

        return toRet;
    }

Мой модульный тест:

    [TestMethod]
    public void Test()
    {
        Assert.AreEqual("A", NumberToExcelColumn(1));
        Assert.AreEqual("Z", NumberToExcelColumn(26));
        Assert.AreEqual("AA", NumberToExcelColumn(27));
        Assert.AreEqual("AO", NumberToExcelColumn(41));
        Assert.AreEqual("AZ", NumberToExcelColumn(52));
        Assert.AreEqual("BA", NumberToExcelColumn(53));
        Assert.AreEqual("ZZ", NumberToExcelColumn(702));
        Assert.AreEqual("AAA", NumberToExcelColumn(703));
        Assert.AreEqual("ABC", NumberToExcelColumn(731));
        Assert.AreEqual("ACQ", NumberToExcelColumn(771));
        Assert.AreEqual("AYZ", NumberToExcelColumn(1352));
        Assert.AreEqual("AZA", NumberToExcelColumn(1353));
        Assert.AreEqual("AZB", NumberToExcelColumn(1354));
        Assert.AreEqual("BAA", NumberToExcelColumn(1379));
        Assert.AreEqual("CNU", NumberToExcelColumn(2413));
        Assert.AreEqual("GCM", NumberToExcelColumn(4823));
        Assert.AreEqual("MSR", NumberToExcelColumn(9300));
        Assert.AreEqual("OMB", NumberToExcelColumn(10480));
        Assert.AreEqual("ULV", NumberToExcelColumn(14530));
        Assert.AreEqual("XFD", NumberToExcelColumn(16384));
    }

+1 для отображения максимальной ссылки на ячейку в ваших тестах (XFD) - вы не поверите, насколько сложно найти эту информацию в Интернете.

controlbox 15.12.2019 18:26

Совпадающая и элегантная версия Рубин:

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

Мне просто нужно было проделать эту работу сегодня, моя реализация использует рекурсию:

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)

Реализация 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

Реализация 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;
},

Спасибо Преобразование алфавита столбца 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://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;
}

Видел еще один ответ VBA - это можно сделать в с однострочным UDF:

Function GetColLetter(ByVal colID As Integer) As String
    GetColLetter = Split(Cells(1, colID).Address, "$")(1)
End Function

Хотя я опаздываю в игру, Ответ Грэма далеко не оптимален. В частности, вам не нужно использовать modulo, вызовите ToString() и примените приведение (int). Учитывая, что в большинстве случаев в мире C# вы начинаете нумерацию с 0, вот моя редакция:

public static string GetColumnName(int index) // zero-based
{
    const byte BASE = 'Z' - 'A' + 1;
    string name = String.Empty;

    do
    {
        name = Convert.ToChar('A' + index % BASE) + name;
        index = index / BASE - 1;
    }
    while (index >= 0);

    return name;
}

Миниатюра Microsoft Excel, формула быстрого и грязного.

Привет,

Вот один из способов получить заголовок столбца символов Excel из числа ....

Я создал формулу для ячейки Excel.

(т.е. я отказался от программирования на VBA.)

Формула смотрит на ячейку, в которой есть число, и сообщает вам, что это за столбец - буквами.

На прикрепленном изображении:

  • Я помещаю 1,2,3 и т. д. В верхний ряд до столбца ABS.
  • Я вставил свою формулу во второй ряд до АБС.
  • Моя формула смотрит на строку 1 и преобразует число в идентификатор заголовка столбца Excel.
  • Моя формула работает для всех чисел до 702 (zz).
  • Я сделал это таким образом, чтобы доказать, что формула работает, чтобы вы могли посмотреть на результат формулы, посмотреть на заголовок столбца выше и легко визуально убедиться, что формула работает. :-)

    = СЦЕПИТЬ (MID ("_ abcdefghijklmnopqrstuvwxyz", (IF (MOD (K1,26)> 0, INT (K1 / 26) +1, (INT (K1 / 26))))), 1), MID ("abcdefghijklmnopqrstuvwxyz", ЕСЛИ (MOD (K1,26) = 0,26, MOD (K1,26)), 1))

Подчеркивание использовалось для целей отладки - чтобы вы знали, что на самом деле есть пробел и что оно работает правильно.

С этой формулой выше - что бы вы ни поместили в K1 - формула сообщит вам, каким будет заголовок столбца.

Формула в ее нынешнем виде состоит только из двух цифр (ZZ), но ее можно изменить, добавив третью букву (ZZZ).

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


and the opposite direction:
// 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

Просто добавьте простую двухстрочную реализацию C# с использованием рекурсии, потому что все ответы здесь кажутся гораздо более сложными, чем необходимо.

/// <summary>
/// Gets the column letter(s) corresponding to the given column number.
/// </summary>
/// <param name = "column">The one-based column index. Must be greater than zero.</param>
/// <returns>The desired column letter, or an empty string if the column number was invalid.</returns>
public static string GetColumnLetter(int column) {
    if (column < 1) return String.Empty;
    return GetColumnLetter((column - 1) / 26) + (char)('A' + (column - 1) % 26);
}

Это вопрос для всех остальных, а также для перенаправления 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)

Это будет очень похоже на многих языках, поэтому вы можете адаптировать его по мере необходимости.

Опять же, используйте это только в том случае, если вы на 100% уверены, что у вас не будет больше 26 столбцов.

Спасибо за ответы здесь !! помог мне придумать эти вспомогательные функции для некоторого взаимодействия с API Google Sheets, над которым я работаю в Elixir / Phoenix

вот что я придумал (возможно, можно было бы использовать дополнительную проверку и обработку ошибок)

В Эликсире:

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

Извините, это Python вместо C#, но, по крайней мере, результаты верны:

def excel_column_number_to_name(column_number):
    output = ""
    index = column_number-1
    while index >= 0:
        character = chr((index%26)+ord('A'))
        output = output + character
        index = index/26 - 1

    return output[::-1]


for i in xrange(1, 1024):
    print "%4d : %s" % (i, excel_column_number_to_name(i))

Пройдены эти тестовые случаи:

  • Номер столбца: 494286 => ABCDZ
  • Номер столбца: 27 => AA
  • Номер столбца: 52 => AZ

Это версия 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;
};

Вот код Грэма на Powershell:

function ConvertTo-ExcelColumnID {
param (
    [parameter(Position = 0,
        HelpMessage = "A 1-based index to convert to an excel column ID. e.g. 2 => 'B', 29 => 'AC'",
        Mandatory = $true)]
    [int]$index
);

[string]$result = '';
if ($index -le 0 ) {
    return $result;
}

while ($index -gt 0) {
    [int]$modulo = ($index - 1) % 26;
    $character = [char]($modulo + [int][char]'A');
    $result = $character + $result;
    [int]$index = ($index - $modulo) / 26;
}

return $result;

}

Большинство предыдущих ответов верны. Вот еще один способ преобразования номера столбца в столбцы Excel. решение довольно простое, если рассматривать это как базовое преобразование. Просто преобразуйте номер столбца в основание 26, так как всего 26 букв. Вот как это можно сделать:

шаги:

  • установить столбец как частное

  • вычтите единицу из переменной частного (из предыдущего шага), потому что нам нужно получить таблица ascii, где 97 будет.

  • разделите на 26 и получите остаток.

  • добавить +97 к остатку и преобразовать в char (поскольку 97 - это "a" в таблице ASCII)
  • частное становится новым частным / 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())

Уже более 30 решений, но вот мое однострочное решение на C# ...

public string IntToExcelColumn(int i)
{
    return ((i<16926? "" : ((char)((((i/26)-1)%26)+65)).ToString()) + (i<2730? "" : ((char)((((i/26)-1)%26)+65)).ToString()) + (i<26? "" : ((char)((((i/26)-1)%26)+65)).ToString()) + ((char)((i%26)+65)));
}

Вот мое решение на питоне

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)

Машинопись

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;
}

Кажется, что многие ответы намного сложнее, чем необходимо. Вот общий ответ 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

Это частый вопрос, который задают при тестировании кодирования. у него есть некоторые ограничения: максимальное количество столбцов в строке = 702 вывод должен иметь номер строки + имя столбца, например. для 703 ответ 2А. (примечание: я только что изменил существующий код из другого ответа) вот код того же:

    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;
    }
}

T-SQL (SQL СЕРВЕР 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;

Вот более простое решение для индекса столбца с нулевым индексом

 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)}";
        }

Другие вопросы по теме