Bir sütun numarası (örn. 127) Excel sütununa (örneğin AA) dönüştürme


474

Değeri doğrudan Excel'den alma otomasyonu kullanmadan sayısal bir sayıyı C # 'da Excel sütun adına nasıl dönüştürürsünüz.

Excel 2007'de, desteklediği sütun sayısı olan 1 ila 16384 arasında olası bir aralık vardır. Ortaya çıkan değerler excel sütun adları biçiminde olmalıdır, örneğin A, AA, AAA vb.


1
Unutulmamalıdır ki mevcut sütun sayısında sınırlar vardır. * * Excel 2003 (v11) IV, 2 ^ 8 veya 256 sütuna kadar çıkmaktadır). * Excel 2007 (v12) XFD, 2 ^ 14 veya 16384 sütunlara kadar gider.
dilimlenmemiş


Bu soru C # ve excel olarak etiketlenmiştir. Bu soruyu modası geçmiş olarak işaretliyorum , çünkü 2016'da yaşıyoruz ve EPPLUS var . Sunucuda gelişmiş Excel elektronik tabloları oluşturmak için yaygın olarak kullanılan bir C # kitaplığı. Bu, GNU Kütüphanesi Genel Kamu Lisansı (LGPL) altında sunulmaktadır. EPPlus'ı kullanarak Sütun dizesini kolayca alabilirsiniz.
Tony_KiloPapaMikeGolf

Satır ve sütun sınırlarının dosya biçimine Excel sürümünden daha fazla bağlı olduğunu ve her çalışma kitabı için farklı olabileceğini unutmayın. Daha eski veya daha yeni bir biçime kaydedildiyse aynı çalışma kitabı için bile değişebilirler.
Slai

Yanıtlar:


901

İşte nasıl yaparım:

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
Bu kod iyi çalışıyor. Sütun A'nın sütunNumara 1 olduğunu varsayar. Sütun A'yı SütunNumarası 0 olarak kullanarak sistemimi hızlı bir şekilde değiştirmek zorunda kaldım. İnt dividend = columnNumber + 1 olarak satır int temettü değiştirdim; Keith
Keith Sirmons

14
@Jduv sadece kullanarak denedi StringBuilder. Yaklaşık iki kat daha uzun sürer. Çok kısa bir dize (maksimum 3 karakter - Excel 2010 XFD sütununa kadar çıkıyor), bu nedenle maksimum 2 dize birleşimi. (Test olarak 1 ila 16384 tamsayılarını çevirmek için 100 yineleme kullandım, yani Excel sütunları A'dan XFD'ye).
Graham

18
Daha iyi anlamak için, 65'i 'A' ile değiştiririm
Stef Heyenrath

11
Bence 65 yerine 'A' kullanmak daha iyi olur. Ve 26 ('Z' - 'A' + 1) olarak değerlendirilebilir, örneğin: const int AlphabetLength = 'Z' - 'A' + 1;
Denis Gladkiy

5
Ben oyuna geç kaldım rağmen, kod uzak optimal.Particularly olmaktan, kullanmak zorunda kalmamasıdır modulo, çağrıyı ToString()ve uygulamak (int)döküm. C # dünyasında çoğu durumda 0'dan numaralamaya başlayacağınızı düşünürsek, benim revizyonum: <! - dil: c # -> genel statik dize GetColumnName (int dizin) // sıfır tabanlı {const byte BASE = 'Z '-' A '+ 1; string name = String.Empty; do {name = Convert.ToChar ('A' +% BASE dizini) + adı; dizin = dizin / BASE - 1; } while (dizin> = 0); dönüş adı; }
Herman Kan

63

Herhangi birinin bunu VBA olmadan Excel'de yapması gerekiyorsa, işte bir yol:

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

burada colNum sütun numarasıdır

Ve VBA'da:

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
Örnek: = YERİNEKOY (METİN (ADRES (1,1000,4), ""), "1", "")
Dolph

Evet, Excel'i bir yerel ayarda kullanıyorum; , Excel'deki işlev bağımsız değişkenlerini ayırmak için kullanılır. Bunu işaret ettiğiniz için teşekkürler.
vzczc

2
Bunu METİN işlevi olmadan yaptım. METİN işlevinin amacı nedir?
dayuloli

2
@dayuloli Bu cevabın yazılmasından bu yana uzun zaman önce haklısınız, METİN fonksiyonu burada bir amaca hizmet etmiyor. Cevabı güncelleyecek.
vzczc

21

Üzgünüz, bu C # yerine Python, ancak en azından sonuçlar doğrudur:

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

Evet aşağı düştüm, soru C # olduğunda Python göndermeyin. Ve evet, daha fazla insan bunu yapmalı.
KyloRen

1
Sorunun başlığı C # anlamına gelmez, bu yüzden birçok kişi buraya gelmez C #. Bu nedenle, Python'da paylaştığınız için teşekkürler!
Tim-Erwin

20

Her iki şekilde de dönüşüm yapmanız gerekebilir, örneğin AAZ gibi Excel sütun adresinden tamsayıya ve herhangi bir tamsayıdan Excel'e. Aşağıdaki iki yöntem tam da bunu yapacaktır. 1 tabanlı dizin oluşturmayı varsayar, "dizilerinizdeki ilk öğe öğe numarası 1'dir. Burada boyutla ilgili sınır yoktur, bu nedenle ERROR gibi adresleri kullanabilirsiniz ve bu 2613824 sütun numarası olacaktır ...

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

İlk yazımda bir hata buldum, bu yüzden oturmaya ve matematik yapmaya karar verdim. Bulduğum, Excel sütunlarını tanımlamak için kullanılan sayı sisteminin, başka bir kişinin yayınladığı gibi bir temel 26 sistemi olmadığıdır. Taban 10'da aşağıdakileri göz önünde bulundurun. Bunu alfabenin harfleriyle de yapabilirsiniz.

Boşluk: ......................... S1, S2, S3: S1, S2, S3
............ ........................ 0, 00, 000: .. A, AA, AAA
............. ....................... 1, 01, 001: .. B, AB, AAB
.............. ......................…,…,…: ..…,…,…
............... ..................... 9, 99, 999: .. Z, ZZ, ZZZ
Uzayda Toplam Durum: 10, 100, 1000: 26, 676, 17576
Toplam Eyaletler: ............... 1110 ................ 18278

Excel, 26 tabanını kullanarak tek tek alfabetik boşluklardaki sütunları numaralandırır. Genel olarak, durum alanı ilerlemesinin bazı taban a için a, a ^ 2, a ^ 3,… olduğunu ve toplam durum sayısının + a olduğunu görebilirsiniz. ^ 2 + a ^ 3 +….

İlk N boşluğundaki toplam A durumu sayısını bulmak istediğinizi varsayalım. Bunu yapmak için formül A = (a) (a ^ N - 1) / (a-1) 'dir. Bu önemlidir, çünkü indeksimiz K'ye karşılık gelen N alanını bulmamız gerekir. K'nin sayı sisteminde nerede bulunduğunu bulmak istersem, A'yı K ile değiştirmem ve N için çözmem gerekir. Çözüm N = log { baz a} (A (a-1) / a +1). A = 10 ve K = 192 örneğini kullanırsam, N = 2.23804… olduğunu biliyorum. Bu bana K'nin üçüncü alanın başında olduğunu ve ikiden biraz daha büyük olduğunu söylüyor.

Bir sonraki adım, mevcut alanda tam olarak ne kadar olduğumuzu bulmaktır. Bunu bulmak için, N'nin tabanı kullanılarak oluşturulan KA'dan çıkar. Bu örnekte, N'nin tabanı ikidir. Dolayısıyla, ilk iki boşluğun durumlarını birleştirdiğinizde beklendiği gibi A = (10) (10 ^ 2 - 1) / (10-1) = 110. Bu K'den çıkarılmalıdır, çünkü bu ilk 110 durum ilk iki alanda zaten açıklanmış olacaktı. Bu bizi 82 eyalete bırakıyor. Yani, bu sayı sisteminde, taban 10'da 192'nin temsili 082'dir.

Sıfır temel indeksi kullanan C # kodu:

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

// Eski Gönderi

C # 'da sıfır tabanlı bir çözüm.

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

ooh neden bilmiyorum ama bu çözümü seviyorum. Hiçbir şey fantezi sadece iyi mantık kullanımı ... programcı seviyeleri için kolayca okunabilir kod. Bir şey olsa da, dize aralığı = string.Empty olarak boş bir dize C # belirtmek için en iyi uygulama inanıyorum;
İsimsiz Tip

Evet, çok güzel bir açıklama. Ama aynı zamanda bunun taban 27 olmadığını da söyleyebilir misiniz? Açıklamanız bunu incelendiğinde gösterir, ancak üst kısımda hızlı bir şekilde bahsedilmesi birkaç kişiyi bir süre kurtarabilir.
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;

Güncelleme : Peter'ın yorumu doğru. Tarayıcıda kod yazmak için aldığım şey bu. :-) Benim çözüm derleme değildi, en soldaki mektup eksikti ve dizeyi ters sırayla inşa ediyordu - hepsi şimdi düzeltildi.

Hataları bir kenara bırakırsak, algoritma temel olarak bir sayıyı 10 tabanından 26 tabanına dönüştürmektedir.

Güncelleme 2 : Joel Coehoorn haklı - yukarıdaki kod 27 için AB döndürecek. Eğer gerçek taban 26 sayı olsaydı, AA A'ya eşit olacak ve Z'den sonraki bir sonraki sayı BA olacaktı.

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;

Kod derlenmeyecek (sCol başlatılmadı). Eğer öyleyse, doğru cevabı vermeyecektir.
Peter

5
BU CEVAP YANLIŞ. Base26 yeterince iyi değil. Sargı Z'den AA'ya ne zaman düşünün. A, 0 basamağına eşdeğerse, 9'dan 00'a kaydırmak gibidir. 1 basamaksa, 9'dan 11'e kaydırmak gibidir.
Joel Coehoorn

4
Güncellemelerden sonra net değilim ... algoritmalardan herhangi biri şimdi doğru mu? Ve eğer öyleyse, hangisi, ikincisi? Bunu düzenler ve gelecek nesiller için
açıklığa kavuştururdum

10

Özyineleme ile kolay.

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
.. ya da bir döngü. Burada özyineleme kullanmak için gerçek bir neden yoktur.
Blorgbeard

1
Sadece 26 tabanı değil, özyinelemeli çözüm çok daha basittir.
Joel Coehoorn

Bu rutin aslında işe yaramıyor. Örneğin GetStandardExcelColumnName (26), @ GetStandardExcelColumnName (52) döndürür B @ döndürür
sgmoore

1
"en basit" çözümün aksine en açık olan en iyisidir.
İsimsiz Tip

9

Sadece özyineleme kullanarak basit bir iki satır C # uygulama atma, çünkü burada tüm cevaplar gerekenden çok daha karmaşık görünüyor.

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

..Ve php'ye dönüştürüldü:

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 yerine kullanın .
Mulli

8

Şimdiye kadar tüm çözümlerin yineleme veya özyineleme içerdiğine şaşırdım.

İşte sabit zamanda çalışan çözümüm (döngüler yok). Bu çözüm tüm olası Excel sütunları için çalışır ve girişin bir Excel sütununa dönüştürülebildiğini kontrol eder. Olası sütunlar [A, XFD] veya [1, 16384] aralığındadır. (Bu, Excel sürümünüze bağlıdır)

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
Bilginize: @ Graham'ın yanıtı (ve muhtemelen diğerleri) sizinkinden daha geneldir: sütun adlarında 4+ karakteri destekler. İşte bu yüzden yinelemeli.
bernard paulus

Aslında, ints değil sınırsız tamsayı kullanırlarsa , sonuçta elde edilen sütun adı keyfi olarak uzun olabilir (örneğin, python cevabı için geçerlidir)
bernard paulus

1
Verilerim 16.384 sütunlu bir e-tablo için çok büyükse, kendimi kafamdan vururum. Her neyse, Excel olası üç harfli sütunların tümünü bile desteklemiyor (XFD'de kesiliyor 1.894 sütun bırakarak). Neyse şimdi. Cevabımı gelecekte gerektiği gibi güncelleyeceğim.
user2023861

:) bunu bilmiyordum! Benim yorumum farklı algoritmaların teorik özellikleri üzerineydi.
bernard paulus

Bu muhtemelen en basit ve en net çözümdür.
Juan

8

Bu cevap javaScript'te:

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 ile aynı uygulama

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

Burada verilen tüm Sürümlere baktıktan sonra, özyineleme kullanarak kendim yapmak için karar verdim.

İşte benim vb.net Sürüm:

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

Oyuna biraz geç kaldım, ama kullandığım kod (C # 'da):

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
Sorulanın tersini yaptınız, ama lambda-fu'nuz için +1.
nurettin

IndexOfoldukça yavaşsa, ters eşlemeyi önceden hesaplamanız daha iyi olur.
Vlad

5

Col indeksi ve col Label arasında birlikte çalışma için kullandığım statik sınıfımı atmak istedim. Benim ColumnLabel Yöntemi için değiştirilmiş kabul edilen bir cevap kullanın

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

Bunu şu şekilde kullanın ...

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

4

sadece kodu olmayan bir hücre formülü için istiyorsanız, bunun için bir formül:

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

4

Delphi'de (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;

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

Tam olarak 26 değil, sistemde 0 yoktur. Eğer olsaydı, 'Z'yi' AA 'değil' BA 'izlerdi.


3

Perl'de, 1 (A), 27 (AA) vb. Giriş için.

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

Orijinal çözümün iyileştirilmesi (C # ile):

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

İşte bir Actionscript sürümü:

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 Çözümü

/**
 * 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
Dizin 26 ve 27'yi deneyin. Çok yakın, ancak birer birer kapalı.
Eric

değer = Math.floor (değer / 26); değer = Math.ceil (değer / 26) -1 olmalıdır;
Henry Liu

2

Bunlar benim kodları belirli bir sayı (dizin başlangıç ​​1) Excel Sütun dönüştürmek için.

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

Birim Testim:

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

Testlerinizde maksimum hücre referansının ne olduğunu göstermek için +1 (XFD) - bu bilgiyi web'de bulmanın ne kadar zor olduğuna inanmazsınız.
kontrol kutusu

2

Oyuna geç kaldığım halde Graham'ın cevabı optimal olmaktan çok uzak. Özellikle, cast'ı kullanmak modulo, aramak ToString()ve uygulamak zorunda değilsiniz (int). C # dünyasında çoğu durumda 0'dan numaralamaya başlayacağınız düşünüldüğünde, işte benim revizyonum:

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

Başka bir VBA yolu

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

1

İşte benim PHP benim süper geç uygulaması. Bu özyinelemeli. Bu yazıyı bulmadan hemen önce yazdım. Başkalarının bu sorunu zaten çözüp çözmediğini görmek istedim ...

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'da aynı şeyi yapmaya çalışıyorum ... Aşağıdaki kodu yazdım:

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

Şimdi columnNumber = 29 ile çalıştırdığımda, bana ne = ne eksik sonuç "" CA "(" AC "yerine) verir? StringBuilder tarafından tersine çevirebileceğimi biliyorum .... Ama Graham'ın cevabına baktığımda biraz kafam karıştı ....


Graham diyor ki: columnName = Convert.ToChar(65 + modulo).ToString() + columnName(yani değer + ColName). Hasan diyor ki: columnName += val;(yani colName + değeri)
mcalex

Eklemek yerine yeni karakteri ekliyorsunuz. Olmalı columnName = columnName + val.
Domenic D.

1

Tesadüf ve zarif Ruby versiyonu:

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

Bu, diğerlerinin yanı sıra Google'ın yönlendirdiği soru, bu yüzden buraya gönderiyorum.

Bu yanıtların çoğu doğrudur, ancak 26'dan fazla sütuna sahip olmadığınız zamanlar gibi basit durumlar için çok hantaldır. Çift karakter sütunlarına girip giremeyeceğinizden şüphe ediyorsanız, bu yanıtı göz ardı edin, ancak yapmayacağınızdan eminseniz, C # 'da bu kadar basit yapabilirsiniz:

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, geçtiğiniz şeyden eminseniz, doğrulamayı kaldırabilir ve bu satır içi kullanabilirsiniz:

(char)('A' + index)

Bu, birçok dilde çok benzer olacaktır, böylece gerektiği gibi uyarlayabilirsiniz.

Yine, bunu yalnızca 26 sütundan fazla olmayacağınızdan% 100 eminseniz kullanın .


1

Burada cevaplar için teşekkürler !! Elixir / Phoenix'te çalıştığım Google E-Tablolar API'sı ile bazı etkileşimler için bu yardımcı işlevleri bulmama yardımcı oldu

İşte ne geldi (muhtemelen bazı ekstra doğrulama ve hata işleme kullanabilirsiniz)

İksir'de:

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

Ve ters fonksiyon:

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

Ve bazı testler:

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
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.