Cara mengonversi nomor kolom (mis. 127) menjadi kolom Excel (mis. AA)

475

Bagaimana Anda mengonversi angka numerik ke nama kolom Excel di C # tanpa menggunakan otomatisasi mendapatkan nilai langsung dari Excel.

Excel 2007 memiliki kisaran 1 hingga 16384, yang merupakan jumlah kolom yang didukungnya. Nilai yang dihasilkan harus dalam bentuk nama kolom excel, misalnya A, AA, AAA dll.

robertkroll
sumber
1
Tidak lupa bahwa ada batasan jumlah kolom yang tersedia. Misalnya * Excel 2003 (v11) naik ke IV, 2 ^ 8 atau 256 kolom). * Excel 2007 (v12) naik ke XFD, 2 ^ 14 atau 16384 kolom.
Tanpa izin
Pertanyaan ini ditandai C # dan unggul. Saya menandai pertanyaan ini sebagai usang, karena kami hidup pada tahun 2016 dan ada EPPLUS . Pustaka C # yang umum digunakan untuk membuat lembar bentang Excel canggih di server. Yang tersedia di bawah: Lisensi Publik Umum (LGPL) Perpustakaan GNU. Menggunakan EPPlus Anda dapat dengan mudah mendapatkan string Kolom.
Tony_KiloPapaMikeGolf
Perhatikan bahwa batas baris dan kolom lebih tergantung pada format file daripada versi Excel, dan bisa berbeda untuk setiap buku kerja. Mereka dapat mengubah bahkan untuk buku kerja yang sama jika disimpan ke format yang lebih lama atau lebih baru.
Slai

Jawaban:

902

Begini cara saya melakukannya:

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;
}
Graham
sumber
65
Kode ini berfungsi dengan baik. Itu mengasumsikan Kolom A adalah kolomNomor 1. Saya harus membuat perubahan cepat untuk akun sistem saya menggunakan Kolom A sebagai kolomNumber 0. Saya mengubah garis dividen int ke dividen int = columnNumber +1; Keith
Keith Sirmons
14
@ Jduv baru saja mencobanya menggunakan StringBuilder. Butuh sekitar dua kali lebih lama. Ini adalah string yang sangat singkat (maks. 3 karakter - Excel 2010 naik ke kolom XFD), jadi maksimum 2 rangkaian string. (Saya menggunakan 100 iterasi untuk menerjemahkan bilangan bulat 1 hingga 16384, yaitu kolom Excel A ke XFD, sebagai tes).
Graham
18
Untuk pemahaman yang lebih baik, saya akan mengganti 65 dengan 'A'
Stef Heyenrath
11
Saya pikir akan lebih baik menggunakan 'A' daripada 65. Dan 26 dapat dievaluasi sebagai ('Z' - 'A' + 1), misalnya: const int AlphabetLength = 'Z' - 'A' + 1;
Denis Gladkiy
5
Meskipun saya terlambat ke permainan, kodenya masih jauh dari optimal. Khususnya, Anda tidak harus menggunakan modulo, memanggil ToString()dan menerapkan (int)pemeran. Mempertimbangkan bahwa dalam kebanyakan kasus di dunia C # Anda akan mulai penomoran dari 0, inilah revisi saya: <! - bahasa: c # -> public static string GetColumnName (int index) // berbasiskan nol {const byte BASE = 'Z '-' A '+ 1; string name = String.Empty; do {name = Convert.ToChar ('A' + index% BASE) + nama; index = index / BASE - 1; } while (index> = 0); nama kembali; }
Herman Kan
63

Jika ada yang perlu melakukan ini di Excel tanpa VBA, berikut ini caranya:

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

di mana colNum adalah nomor kolom

Dan di 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
vzczc
sumber
2
Contoh: = SUBSTITUTE (TEKS (ALAMAT (1,1000,4), ""), "1", "")
Dolph
Ya, saya menggunakan Excel di tempat di mana; digunakan di tempat, untuk memisahkan argumen fungsi di Excel. Terima kasih telah menunjukkan ini.
vzczc
2
Saya melakukan ini tanpa fungsi TEKS. Apa tujuan dari fungsi TEXT?
dayuloli
2
@ dayuloli Lama sejak jawaban ini ditulis, Anda benar, fungsi TEXT tidak melayani tujuan di sini. Akan memperbarui jawabannya.
vzczc
21

Maaf, ini Python bukan C #, tetapi setidaknya hasilnya benar:

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))
RoMa
sumber
Ya saya downVoted, jangan memposting Python ketika pertanyaannya adalah C #. Dan ya, lebih banyak orang harus melakukan ini.
KyloRen
1
Judul pertanyaan tidak menyiratkan C #, jadi banyak orang mungkin datang ke sini yang tidak mencantumkan C #. Karenanya, terima kasih telah berbagi dalam Python!
Tim-Erwin
20

Anda mungkin perlu konversi kedua arah, misalnya dari alamat kolom Excel seperti AAZ ke integer dan dari integer apa pun ke Excel. Dua metode di bawah ini akan melakukan hal itu. Asumsikan 1 pengindeksan berbasis, elemen pertama dalam "array" Anda adalah elemen nomor 1. Tidak ada batasan pada ukuran di sini, sehingga Anda dapat menggunakan alamat seperti ERROR dan itu akan menjadi nomor kolom 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;
}
Arent Arntzen
sumber
13

Saya menemukan kesalahan dalam posting pertama saya, jadi saya memutuskan untuk duduk dan melakukan perhitungan. Apa yang saya temukan adalah bahwa sistem angka yang digunakan untuk mengidentifikasi kolom Excel bukanlah sistem basis 26, seperti yang diposkan orang lain. Pertimbangkan hal-hal berikut dalam basis 10. Anda juga dapat melakukan ini dengan huruf-huruf alfabet.

Spasi: ......................... S1, S2, S3: S1, S2, S3
............ ........................ 0, 00, 000: .. A, AA, AAA
............. ....................... 1, 01, 001: .. B, AB, AAB
.............. ...................... ..., ..., ...: .. ..., ..., ...
............... ..................... 9, 99, 999: .. Z, ZZ, ZZZ
Total status dalam ruang: 10, 100, 1000: 26, 676, 17576
Total Negara: ............... 1110 ................ 18278

Kolom angka Excel dalam spasi alfabet individual menggunakan basis 26. Anda dapat melihat bahwa secara umum, perkembangan ruang keadaan adalah a, a ^ 2, a ^ 3, ... untuk beberapa basis a, dan jumlah total state adalah a + a ^ 2 + a ^ 3 +….

Misalkan Anda ingin menemukan jumlah total negara bagian A dalam ruang N pertama. Rumus untuk melakukannya adalah A = (a) (a ^ N - 1) / (a-1). Ini penting karena kita perlu menemukan ruang N yang sesuai dengan indeks kita K. Jika saya ingin mencari tahu di mana K terletak pada sistem angka saya perlu mengganti A dengan K dan menyelesaikannya untuk N. Solusinya adalah N = log { base a} (A (a-1) / a +1). Jika saya menggunakan contoh a = 10 dan K = 192, saya tahu bahwa N = 2.23804…. Ini memberitahu saya bahwa K terletak di awal ruang ketiga karena sedikit lebih besar dari dua.

Langkah selanjutnya adalah menemukan dengan tepat seberapa jauh jarak kita saat ini. Untuk menemukan ini, kurangi dari K a yang dihasilkan menggunakan lantai N. Dalam contoh ini, lantai N adalah dua. Jadi, A = (10) (10 ^ 2 - 1) / (10-1) = 110, seperti yang diharapkan ketika Anda menggabungkan keadaan dari dua spasi pertama. Ini perlu dikurangi dari K karena 110 negara bagian pertama ini sudah diperhitungkan dalam dua ruang pertama. Ini membuat kita memiliki 82 negara. Jadi, dalam sistem bilangan ini, representasi 192 dalam basis 10 adalah 082.

Kode C # menggunakan indeks dasar nol adalah

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

// Old Post

Solusi berbasis nol di 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;
    }
John
sumber
ooh saya tidak tahu mengapa tetapi saya suka solusi ini. Tidak ada yang mewah hanya menggunakan logika ... kode mudah dibaca untuk tingkat programmer. Namun satu hal, saya percaya praktik terbaiknya untuk menentukan string kosong di C # sebagai string range = string.Empty;
Jenis Anonim
Ya, penjelasan yang sangat bagus. Tapi bisakah Anda juga menyatakan bahwa itu bukan basis 27 juga? Penjelasan Anda menunjukkan ini ketika dipelajari, tetapi penyebutan cepat di atas dapat menghemat waktu beberapa orang.
Marius
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;

Pembaruan : Komentar Peter benar. Itulah yang saya dapatkan untuk menulis kode di browser. :-) Solusi saya tidak mengkompilasi, itu kehilangan surat paling kiri dan sedang membangun string dalam urutan terbalik - semua sekarang diperbaiki.

Selain bug, algoritma ini pada dasarnya mengubah angka dari basis 10 ke basis 26.

Pembaruan 2 : Joel Coehoorn benar - kode di atas akan mengembalikan AB untuk 27. Jika itu nomor basis nyata 26, AA akan sama dengan A dan nomor berikutnya setelah Z akan menjadi 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;
Franci Penov
sumber
Kode tidak akan dikompilasi (sCol tidak diinisialisasi). Jika ya, itu tidak akan memberikan jawaban yang benar.
Peter
5
JAWABAN INI SALAH. Base26 tidak cukup baik. Pikirkan tentang apa yang terjadi ketika bungkus Anda dari Z ke AA. Jika A setara dengan 0 digit, maka itu seperti membungkus dari 9 hingga 00. Jika itu adalah 1 digit, itu seperti membungkus dari 9 hingga 11.
Joel Coehoorn
4
Saya tidak jelas setelah pembaruan ... apakah salah satu dari algoritma itu sekarang benar? Dan jika demikian, yang mana, yang kedua? Saya akan menyunting ini dan membuatnya jelas untuk anak cucu ....
JoeCool
10

Mudah dengan rekursi.

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) );
}
Peter
sumber
1
.. atau satu lingkaran. Tidak ada alasan nyata untuk menggunakan rekursi di sini.
Blorgbeard keluar
1
Ini bukan hanya basis 26, jadi solusi rekursif jauh lebih sederhana.
Joel Coehoorn
Rutinitas ini sebenarnya tidak berhasil. Misalnya GetStandardExcelColumnName (26) mengembalikan @ GetStandardExcelColumnName (52) mengembalikan B @
sgmoore
1
solusi yang paling jelas sebagai lawan solusi "paling sederhana" adalah yang terbaik.
Jenis Anonim
9

Hanya melempar implementasi C # dua baris sederhana menggunakan rekursi, karena semua jawaban di sini tampaknya jauh lebih rumit daripada yang diperlukan.

/// <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);
}
Extragorey
sumber
8

..Dan dikonversi ke php:

function GetExcelColumnName($columnNumber) {
    $columnName = '';
    while ($columnNumber > 0) {
        $modulo = ($columnNumber - 1) % 26;
        $columnName = chr(65 + $modulo) . $columnName;
        $columnNumber = (int)(($columnNumber - $modulo) / 26);
    }
    return $columnName;
}
Stephen Fuhry
sumber
Gunakan ord('A')sebagai ganti 65.
Mulli
8

Saya terkejut semua solusi sejauh ini mengandung iterasi atau rekursi.

Inilah solusi saya yang berjalan dalam waktu yang konstan (tanpa loop). Solusi ini berfungsi untuk semua kolom Excel yang mungkin dan memeriksa apakah input dapat diubah menjadi kolom Excel. Kolom yang mungkin ada dalam kisaran [A, XFD] atau [1, 16384]. (Ini tergantung pada versi Excel Anda)

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);
    }
}
pengguna2023861
sumber
2
FYI: Jawaban @ Graham (dan mungkin yang lain) lebih umum daripada jawaban Anda: mereka mendukung 4+ karakter dalam nama kolom. Dan itulah tepatnya mengapa mereka berulang.
bernard paulus
Bahkan, jika mereka menggunakan bilangan bulat tak terbatas dan bukan ints, nama kolom yang dihasilkan bisa panjang sembarangan (misalnya kasus jawaban python, misalnya)
bernard paulus
1
Jika data saya terlalu besar untuk spreadsheet 16.384 kolom, saya akan menembak kepala saya sendiri. Bagaimanapun, Excel bahkan tidak mendukung semua kolom tiga huruf yang mungkin (itu terputus di XFD meninggalkan 1.894 kolom). Sekarang juga. Saya akan memperbarui jawaban saya di masa yang akan datang.
user2023861
:) tidak tahu itu! Komentar saya ada pada properti teoretis dari berbagai algoritma.
bernard paulus
Yang ini mungkin solusi paling sederhana dan paling jelas.
Juan
8

Jawaban ini dalam 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;
}
MaVRoSCy
sumber
6

Implementasi yang sama di Jawa

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; 
    }  
Balaji.NS
sumber
5

Setelah melihat semua Versi yang disediakan di sini, saya memutuskan untuk melakukannya sendiri, menggunakan rekursi.

Ini Versi vb.net saya:

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
pengguna932708
sumber
5

Sedikit terlambat ke gim, tapi inilah kode yang saya gunakan (dalam 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));
}
Kelly L.
sumber
2
Anda melakukan kebalikan dari yang diminta, tetapi memberi +1 untuk lambda-fu Anda.
nurettin
IndexOfcukup lambat, lebih baik Anda precalcuate pemetaan terbalik.
Vlad
5

Saya ingin melempar di kelas statis saya gunakan, untuk interoping antara indeks col dan Label col. Saya menggunakan jawaban yang diterima yang dimodifikasi untuk Metode ColumnLabel saya

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

Gunakan ini seperti ...

30.ColumnLabel(); // "AD"
"AD".ColumnIndex(); // 30
t3dodson
sumber
4

jika Anda hanya menginginkannya untuk formula sel tanpa kode, berikut ini rumus untuknya:

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

Dalam Delphi (Pascal):

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;
JRL
sumber
3
private String getColumn(int c) {
    String s = "";
    do {
        s = (char)('A' + (c % 26)) + s;
        c /= 26;
    } while (c-- > 0);
    return s;
}

Ini bukan basis 26, tidak ada 0 dalam sistem. Jika ada, 'Z' akan diikuti oleh 'BA' bukan oleh 'AA'.

rubberduckie
sumber
3

Dalam perl, untuk input 1 (A), 27 (AA), dll.

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;
}
Myforwik
sumber
2

Menyempurnakan solusi asli (dalam 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;
    }
}
ShloEmi
sumber
2

Ini adalah versi 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;
    }
rampok
sumber
2

Solusi 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;
};
Sekutu
sumber
1
Coba indeks 26 dan 27. Sangat dekat, tetapi tidak aktif satu.
Eric
value = Math.floor (value / 26); harus bernilai = Math.ceil (nilai / 26) - 1;
Henry Liu
2

Ini kode saya untuk mengonversi angka tertentu (indeks mulai dari 1) ke Kolom 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;
    }

Tes Unit Saya:

    [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));
    }
Stevanus
sumber
+1 untuk menunjukkan apa referensi sel maksimum dalam pengujian Anda (XFD) - Anda tidak akan percaya betapa sulitnya untuk menemukan info itu di web.
controlbox
2

Meskipun saya terlambat ke permainan, jawaban Graham masih jauh dari optimal. Khususnya, Anda tidak harus menggunakan modulo, memanggil ToString()dan melamar (int). Menimbang bahwa dalam kebanyakan kasus di dunia C # Anda akan mulai memberi penomoran mulai dari 0, inilah revisi saya:

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;
}
Herman Kan
sumber
2

Cara VBA lain

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

Inilah implementasi saya yang sangat terlambat di PHP. Yang ini bersifat rekursif. Saya menulisnya tepat sebelum saya menemukan posting ini. Saya ingin melihat apakah orang lain sudah menyelesaikan masalah ini ...

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;
}
Ian Atkin
sumber
1

Saya mencoba melakukan hal yang sama di Jawa ... Saya telah menulis kode berikut:

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

Sekarang setelah saya menjalankannya dengan columnNumber = 29, itu memberi saya hasil = "CA" (bukannya "AC") ada komentar apa yang saya lewatkan? Saya tahu saya bisa membalikkannya dengan StringBuilder .... Tetapi melihat jawaban Graham, saya agak bingung ....

Hasan
sumber
Graham mengatakan: columnName = Convert.ToChar(65 + modulo).ToString() + columnName(yaitu nilai + ColName). Hasan mengatakan: columnName += val;(yaitu nilai ColName +)
mcalex
Anda menambahkan karakter baru alih-alih menambahkannya. Seharusnya columnName = columnName + val.
Domenic D.
1

Versi Ruby yang bertepatan dan elegan :

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
Iwan B.
sumber
1

Ini adalah pertanyaan yang diajukan semua orang dan juga Google, jadi saya memposting ini di sini.

Banyak dari jawaban ini yang benar tetapi terlalu rumit untuk situasi sederhana seperti ketika Anda tidak memiliki lebih dari 26 kolom. Jika Anda ragu apakah Anda akan masuk ke kolom karakter ganda kemudian abaikan jawaban ini, tetapi jika Anda yakin tidak akan melakukannya, maka Anda bisa melakukannya sesederhana ini di 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);
}

Heck, jika Anda yakin tentang apa yang Anda sampaikan, Anda bahkan dapat menghapus validasi dan menggunakan inline ini:

(char)('A' + index)

Ini akan sangat mirip dalam banyak bahasa sehingga Anda dapat menyesuaikannya sesuai kebutuhan.

Sekali lagi, hanya gunakan ini jika Anda 100% yakin Anda tidak akan memiliki lebih dari 26 kolom .

Vlad Schnakovszki
sumber
1

Terima kasih atas jawabannya di sini !! membantu saya menemukan fungsi pembantu ini untuk beberapa interaksi dengan Google Sheets API yang saya kerjakan di Elixir / Phoenix

inilah yang saya buat (mungkin bisa menggunakan beberapa validasi dan penanganan kesalahan tambahan)

Dalam 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

Dan fungsi terbalik:

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

Dan beberapa tes:

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
phlare
sumber