Як перетворити номер стовпця (наприклад, 127) у стовпець Excel (наприклад, AA)


474

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

У Excel 2007 можливий діапазон від 1 до 16384, тобто кількість стовпців, які він підтримує. Отримані значення повинні бути у вигляді назв стовпців Excel, наприклад A, AA, AAA тощо.


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


Це питання позначено тегами C # та excel. Я вважаю це питання застарілим, оскільки ми живемо у 2016 році і є EPPLUS . Широко використовувана бібліотека C # для створення розширених таблиць Excel на сервері. Який доступний у розділі: Загальна публічна ліцензія бібліотеки GNU (LGPL). Використовуючи EPPlus, ви можете легко отримати рядок Column.
Tony_KiloPapaMikeGolf

Зауважте, що обмеження рядків і стовпців більше залежать від формату файлу, ніж версія Excel, і можуть бути різними для кожної робочої книги. Вони можуть змінюватися навіть для однієї і тієї ж робочої книги, якщо вона збережена у старій чи новій формі.
Слай

Відповіді:


901

Ось як я це роблю:

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

64
Цей код добре працює. Це передбачає, що стовпець A є стовпцемNumber 1. Мені довелося зробити швидку зміну для обліку для моєї системи, використовуючи стовпець A як columnNumber 0. Я змінив рядок int dividend на int dividend = columnNumber + 1; Кіт
Кіт Сірмонс

14
@Jduv просто спробував це, використовуючи StringBuilder. Це займає приблизно вдвічі більше. Це дуже коротка строка (максимум 3 символи - Excel 2010 піднімається до стовпця XFD), тому максимум 2 рядкових конкатенації. (Я використовував 100 ітерацій перекладу цілих чисел 1 на 16384, тобто стовпці Excel в тест як тест).
Грем

18
Для кращого розуміння я замінив би 65 на "А"
Стеф Хейенрат

11
Я думаю, було б краще використовувати «A» замість 65. І 26 можна оцінити як («Z» - «A» + 1), наприклад: const int AlphabetLength = 'Z' - 'A' + 1;
Денис Гладкий

5
Хоча я запізнююся на гру, код далеко не є оптимальним. Особливо, вам не доведеться використовувати modulo, виклик ToString()та застосувати (int)кастинг. Зважаючи на те, що в більшості випадків у світі C # ви б почали нумерацію з 0, ось моя редакція: <! - мова: c # -> публічна статична рядок GetColumnName (int index) // нульова база {const byte BASE = 'Z '-' A '+ 1; ім'я рядка = String.Empty; do {name = Convert.ToChar ('A' + індекс% BASE) + ім'я; індекс = індекс / БАЗА - 1; } while (індекс> = 0); зворотне ім’я; }
Герман Кан

63

Якщо комусь потрібно зробити це в 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

2
Приклад: = СУБСТИТУТ (ТЕКСТ (АДРЕС (1,1000,4), ""), "1", "")
Дельф

Так, я використовую Excel у локалі, де; використовується замість, щоб розділити аргументи функції в Excel. Дякуємо, що вказали на це.
vzczc

2
Я зробив це без функції TEXT. Яке призначення функції TEXT?
денулолі

2
@dayuloli З давнього часу, як ця відповідь була написана, ви правильні, функція TEXT тут не слугує меті. Відповідь буде оновлено.
vzczc

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

1
Назва питання не означає C #, тому багато людей можуть прийти сюди, які не очікують C #. Отже, дякую за спільний доступ до Python!
Тім-Ервін

20

Можливо, вам знадобиться перетворення обох способів, наприклад, з адреси стовпців Excel, як AAZ, до цілого числа, а також з будь-якого цілого числа в Excel. Два наведені нижче способи зроблять саме це. Припускає індексацію на основі 1, першим елементом у ваших "масивах" є елемент № 1. Тут немає обмежень щодо розміру, тому ви можете використовувати адреси, такі як ПОМИЛКА, і це буде номер стовпця 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;
}

13

У першій публікації я виявив помилку, тому вирішив сісти і зайнятися математикою. Я знайшов, що система числення, яка використовується для ідентифікації стовпців 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 + a ^ 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,223804…. Це говорить мені, що K лежить на початку третього простору, оскільки він трохи більше двох.

Наступний крок - точно знайти, наскільки далеко ми в поточному просторі. Щоб знайти це, відніміть з K A 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 string = string.Empty;
Анонімний тип

Так, дуже приємне пояснення. Але чи можете ви також просто сказати, що це не база 27? Ваше пояснення показує це під час вивчення, але швидка згадка на вершині може врятувати декількох інших людей деякий час.
Маріус

10
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 не ініціалізований). Якщо це станеться, він не дасть правильної відповіді.
Пітер

5
ЦЕ ВІДПОВІДЬ НЕПРАВНИЙ. Base26 недостатньо хороший. Подумайте, що станеться, коли ваш перехід від Z до AA. Якщо A еквівалентно цифрі 0, то це як загортання з 9 до 00. Якщо це 1 цифра, це як перегортання від 9 до 11.
Джоель Куехорн

4
Мені не зрозуміло після оновлень ... чи один із алгоритмів зараз правильний? А якщо так, то який, другий? Я б відредагував це і зробив це очевидним для нащадків ....
JoeCool

10

Легко з рекурсією.

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

1
.. або петля. Тут немає жодної реальної причини використовувати рекурсію.
Blorgbeard вийшов

1
Це не лише база 26, тому рекурсивне рішення набагато простіше.
Джоель Куехорн

Ця рутина насправді не працює. Наприклад, GetStandardExcelColumnName (26) повертається @ GetStandardExcelColumnName (52) повертається B @
sgmoore

1
найбільш чітке на відміну від "найпростішого" рішення - найкраще.
Анонімний тип

9

Просто додайте просту дворядкову 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);
}

8

..І перетворений на 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.
Маллі

8

Я здивований, що всі розчини на даний момент містять або ітерацію, або рекурсію.

Ось моє рішення, яке працює в постійний час (без циклів). Це рішення працює для всіх можливих стовпців 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);
    }
}

2
FYI: Відповідь Ґрем (і, мабуть, інші) більш загальна, ніж ваша: вони підтримують 4+ символів у назвах стовпців. І саме тому вони ітеративні.
bernard paulus

Справді, якщо вони використовуються необмежену кількість цілих чисел , а не intз, отримане ім'я стовпця може бути як завгодно довго (це випадок пітона відповіді, наприклад)
Бернарда Паулюс

1
Якщо мої дані коли-небудь занадто великі для електронної таблиці 16384 стовпчиків, я застрелю себе в голову. У будь-якому випадку, Excel навіть не підтримує всі можливі трибуквні стовпці (він обрізається в XFD, залишаючи 1894 стовпців). Зараз у будь-якому випадку. Свою відповідь я в майбутньому оновлю, як потрібно.
користувач2023861

:) не знав цього! Мій коментар стосувався теоретичних властивостей різних алгоритмів.
bernard paulus

Це, мабуть, найпростіше і зрозуміліше рішення.
Хуан

8

Ця відповідь знаходиться у 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;
}

6

Така сама реалізація в 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; 
    }  

5

Переглянувши всі представлені тут версії, я вирішив зробити сам, використовуючи рекурсію.

Ось моя версія 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

5

Трохи пізно до гри, але ось код, який я використовую (у 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));
}

2
Ви зробили зворотне запитання, але +1 для лямбда-фу.
Нуреттін

IndexOfйде досить повільно, вам краще попередньо розрахувати зворотне відображення.
Влад

5

Мені хотілося перейти в свій статичний клас, який я використовую, для взаємодії між індексом col і col Label. Я використовую модифіковану прийняту відповідь для свого методу 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

4

якщо ви просто хочете його для формули комірки без коду, ось формула для неї:

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

4

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

3
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".


3

У перлі, для введення 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;
}

2

Доопрацювання оригінального рішення (в 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;
    }
}

2

Ось версія Actioncript:

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

2

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

1
Спробуйте індекси 26 і 27. Це дуже близько, але відключене.
Ерік

значення = Math.floor (значення / 26); має бути значення = Math.ceil (значення / 26) - 1;
Генрі Лю

2

Ці мої коди для перетворення конкретного числа (індекс починається з 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) - ви б не повірили, як важко знайти цю інформацію в Інтернеті.
контрольний

2

Хоча я запізнююся на гру, відповідь Ґрема далеко не оптимальна. Зокрема, вам не потрібно використовувати функцію " modulocall", "call" 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;
}

2

Ще один спосіб VBA

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

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

Я намагаюся зробити те ж саме в 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

Ви додаєте нового символу, а не попередньо. Повинно бути columnName = columnName + val.
Доменіч Д.

1

Coincis і елегантна версія 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

Це питання всіх інших, а також переадресація 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 стовпців .


1

Дякуємо за відповіді тут !! допомогли мені придумати ці допоміжні функції для деякої взаємодії з 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
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.