Cách chuyển đổi số cột (ví dụ 127) thành cột Excel (ví dụ: AA)


474

Làm cách nào để bạn chuyển đổi một số bằng số thành tên cột Excel trong C # mà không sử dụng tự động hóa lấy giá trị trực tiếp từ Excel.

Excel 2007 có phạm vi có thể từ 1 đến 16384, là số cột mà nó hỗ trợ. Các giá trị kết quả phải ở dạng tên cột excel, ví dụ A, AA, AAA, v.v.


1
Không quên rằng có giới hạn về số lượng cột có sẵn. Ví dụ: * Excel 2003 (v11) lên tới IV, 2 ^ 8 hoặc 256 cột). * Excel 2007 (v12) lên tới các cột XFD, 2 ^ 14 hoặc 16384.
Unsliced


Câu hỏi này được gắn thẻ C # và excel. Tôi đánh dấu câu hỏi này là lỗi thời, bởi vì chúng ta sống trong năm 2016 và có EPPLUS . Thư viện C # thường được sử dụng để tạo bảng tính Excel nâng cao trên máy chủ. Được cung cấp theo: Giấy phép Công cộng GNU (LGPL). Sử dụng EPPlus bạn có thể dễ dàng lấy chuỗi Cột.
Tony_KiloPapaMikeGolf

Lưu ý rằng giới hạn hàng và cột phụ thuộc nhiều hơn vào định dạng tệp so với phiên bản Excel và có thể khác nhau đối với mỗi sổ làm việc. Chúng có thể thay đổi ngay cả đối với cùng một sổ làm việc nếu nó được lưu ở định dạng cũ hơn hoặc mới hơn.
Slai

Câu trả lời:


901

Đây là cách tôi làm điều đó:

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
Mã này hoạt động tốt. Nó giả sử Cột A là cột Số 1. Tôi phải thực hiện thay đổi nhanh chóng cho tài khoản của mình bằng cách sử dụng Cột A làm cột Số 0. Tôi đã thay đổi dòng cổ tức int thành int cổ tức = cộtNumber + 1; Keith
Keith Sirmons

14
@Jduv chỉ cần dùng thử StringBuilder. Phải mất khoảng gấp đôi thời gian. Đó là một chuỗi rất ngắn (tối đa 3 ký tự - Excel 2010 đi lên cột XFD), do đó, tối đa là 2 chuỗi nối. (Tôi đã sử dụng 100 lần lặp để dịch các số nguyên từ 1 đến 16384, tức là các cột Excel A sang XFD, làm bài kiểm tra).
Graham

18
Để hiểu rõ hơn, tôi sẽ thay thế số 65 bằng 'A'
Stef Heyenrath

11
Tôi nghĩ sẽ tốt hơn nếu sử dụng 'A' thay vì 65. Và 26 có thể được đánh giá là ('Z' - 'A' + 1), ví dụ: const int AlphabetLdrops = 'Z' - 'A' + 1;
Denis Gladkiy

5
Mặc dù tôi đến trễ trò chơi, nhưng mã này không được tối ưu. Đặc biệt, bạn không phải sử dụng modulo, gọi ToString()và áp dụng (int)diễn viên. Xem xét rằng trong hầu hết các trường hợp trong thế giới C #, bạn sẽ bắt đầu đánh số từ 0, đây là bản sửa đổi của tôi: <! - ngôn ngữ: c # -> chuỗi tĩnh công khai GetColumnName (int index) // zero-Dựa {const byte BASE = 'Z '-' A '+ 1; tên chuỗi = String.Empty; do {name = Convert.ToChar ('A' + index% BASE) + name; chỉ số = chỉ số / CƠ SỞ - 1; } while (chỉ số> = 0); trả lại tên; }
Herman Kan

63

Nếu bất cứ ai cần làm điều này trong Excel mà không cần VBA, đây là một cách:

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

trong đó colNum là số cột

Và trong 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
Ví dụ: = SUBSTITUTE (TEXT (ĐỊA CHỈ (1,1000,4), ""), "1", "")
Dolph

Có, tôi sử dụng Excel ở một địa phương; được sử dụng thay cho, để tách các đối số hàm trong Excel. Cảm ơn đã chỉ ra điều này.
vzczc

2
Tôi đã làm điều này mà không có chức năng văn bản. Mục đích của hàm TEXT là gì?
dayuloli

2
@dayuloli Đã lâu rồi kể từ khi câu trả lời này được viết, bạn đã đúng, chức năng TEXT không phục vụ mục đích ở đây. Sẽ cập nhật câu trả lời.
vzczc

21

Xin lỗi, đây là Python thay vì C #, nhưng ít nhất kết quả là chính xá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))

Có, tôi đã bỏ phiếu, không đăng Python khi câu hỏi là C #. Và vâng, nhiều người nên làm điều này.
KyloRen

1
Tiêu đề của câu hỏi không ngụ ý C #, vì vậy nhiều người có thể đến đây mà không làm lộ ra C #. Do đó, cảm ơn bạn đã chia sẻ trong Python!
Tim-Erwin

20

Bạn có thể cần chuyển đổi cả hai cách, ví dụ: từ địa chỉ cột Excel như AAZ sang số nguyên và từ bất kỳ số nguyên nào sang Excel. Hai phương pháp dưới đây sẽ làm điều đó. Giả sử lập chỉ mục dựa trên 1, phần tử đầu tiên trong "mảng" của bạn là phần tử số 1. Không có giới hạn về kích thước ở đây, vì vậy bạn có thể sử dụng các địa chỉ như ERROR và đó sẽ là số cột 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

Tôi phát hiện ra một lỗi trong bài đăng đầu tiên của mình, vì vậy tôi quyết định ngồi xuống và làm toán. Những gì tôi tìm thấy là hệ thống số được sử dụng để xác định các cột Excel không phải là một hệ thống cơ sở 26, như một người khác đã đăng. Hãy xem xét những điều sau trong cơ sở 10. Bạn cũng có thể làm điều này với các chữ cái trong bảng chữ cái.

Không gian: ......................... S1, S2, S3: S1, S2, S3
............ ........................ 0, 00, 000: .. A, AA, AAA
............. ....................... 1, 01, 001: .. B, AB, AAB
.............. ...................... ..., ..., ...: .. ..., ..., ...
............... ..................... 9, 99, 999: .. Z, ZZ, ZZZ
Tổng số trạng thái trong không gian: 10, 100, 1000: 26, 676, 17576
Tổng số quốc gia: ............... 1110 ................ 18278

Các cột số Excel trong các không gian theo thứ tự chữ cái riêng lẻ sử dụng cơ sở 26. Bạn có thể thấy rằng nói chung, tiến trình không gian trạng thái là a, a ^ 2, a ^ 3, Khắc cho một số cơ sở a và tổng số trạng thái là a + a ^ 2 + a ^ 3 +.

Giả sử bạn muốn tìm tổng số trạng thái A trong N khoảng trắng đầu tiên. Công thức để làm như vậy là A = (a) (a ^ N - 1) / (a-1). Điều này rất quan trọng vì chúng ta cần tìm không gian N tương ứng với chỉ số của chúng ta K. Nếu tôi muốn tìm ra K nằm ở đâu trong hệ thống số tôi cần thay A bằng K và giải cho N. Giải pháp là N = log { cơ sở a} (A (a-1) / a +1). Nếu tôi sử dụng ví dụ về a = 10 và K = 192, tôi biết rằng N = 2.23804. Điều này cho tôi biết rằng K nằm ở đầu không gian thứ ba vì nó lớn hơn hai một chút.

Bước tiếp theo là tìm chính xác khoảng cách trong không gian hiện tại của chúng ta. Để tìm điều này, hãy trừ đi K the A được tạo bằng cách sử dụng sàn của N. Trong ví dụ này, sàn của N là hai. Vì vậy, A = (10) (10 ^ 2 - 1) / (10-1) = 110, như mong đợi khi bạn kết hợp các trạng thái của hai không gian đầu tiên. Điều này cần phải được trừ khỏi K vì 110 trạng thái đầu tiên này đã được tính trong hai khoảng trống đầu tiên. Điều này để lại cho chúng tôi với 82 tiểu bang. Vì vậy, trong hệ thống số này, đại diện của 192 trong cơ sở 10 là 082.

Mã C # sử dụng chỉ số cơ bản bằng 0 là

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

// Bài cũ

Một giải pháp dựa trên zero trong 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;
    }

ooh tôi không biết tại sao nhưng tôi thích giải pháp này. Không có gì lạ mắt chỉ là sử dụng tốt logic ... mã dễ đọc cho các cấp lập trình viên. Mặc dù vậy, tôi tin rằng cách thực hành tốt nhất của nó là chỉ định một chuỗi rỗng trong C # là chuỗi Range = string.Empty;
Loại ẩn danh

Vâng, giải thích rất tốt đẹp. Nhưng bạn cũng có thể nói rằng nó không phải là căn cứ 27 không? Giải thích của bạn cho thấy điều này khi nghiên cứu, nhưng một đề cập nhanh ở đầu có thể tiết kiệm một số người khác một thời gian.
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;

Cập nhật : Nhận xét của Peter là đúng. Đó là những gì tôi nhận được để viết mã trong trình duyệt. :-) Giải pháp của tôi không được biên dịch, nó bị thiếu chữ cái bên trái nhất và nó đang xây dựng chuỗi theo thứ tự ngược lại - tất cả đã được sửa.

Lỗi sang một bên, thuật toán về cơ bản là chuyển đổi một số từ cơ sở 10 sang cơ sở 26.

Cập nhật 2 : Joel Coehoorn đã đúng - mã ở trên sẽ trả về AB cho 27. Nếu đó là số cơ sở thực 26, thì AA sẽ bằng A và số tiếp theo sau Z sẽ là 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;

Mã sẽ không biên dịch (sCol không được khởi tạo). Nếu có, nó sẽ không đưa ra câu trả lời đúng.
Peter

5
CÂU TRẢ LỜI NÀY LÀ SAI. Base26 không đủ tốt. Hãy suy nghĩ về những gì xảy ra khi bọc của bạn từ Z đến AA. Nếu A tương đương với 0 chữ số, thì nó giống như bọc từ 9 đến 00. Nếu là 1 chữ số, nó giống như gói từ 9 đến 11.
Joel Coehoorn

4
Tôi không rõ sau khi cập nhật ... liệu một trong hai thuật toán có đúng không? Và nếu vậy, cái nào, cái thứ hai? Tôi sẽ chỉnh sửa nó và làm cho nó rõ ràng cho hậu thế ....
JoeCool

10

Dễ dàng với đệ quy.

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
.. hoặc một vòng lặp. Không có lý do thực sự để sử dụng đệ quy ở đây.
Blorgbeard ra mắt

1
Nó không chỉ là cơ sở 26, vì vậy giải pháp đệ quy đơn giản hơn nhiều.
Joel Coehoorn

Thói quen này không thực sự hoạt động. Ví dụ: GetSt ChuẩnExcelColumnName (26) trả về @ GetSt ChuẩnExcelColumnName (52) trả về B @
sgmoore

1
rõ ràng nhất trái ngược với giải pháp "đơn giản nhất" là tốt nhất.
Loại ẩn danh

9

Chỉ cần thực hiện một triển khai C # hai dòng đơn giản bằng cách sử dụng đệ quy, bởi vì tất cả các câu trả lời ở đây có vẻ phức tạp hơn nhiều so với cần thiết.

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

..Và chuyển đổi sang php:

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

Sử dụng ord('A')thay vì 65.
Mulli

8

Tôi ngạc nhiên tất cả các giải pháp cho đến nay có chứa phép lặp hoặc đệ quy.

Đây là giải pháp của tôi chạy trong thời gian không đổi (không có vòng lặp). Giải pháp này hoạt động cho tất cả các cột Excel có thể và kiểm tra xem đầu vào có thể được chuyển thành cột Excel không. Các cột có thể nằm trong phạm vi [A, XFD] hoặc [1, 16384]. (Điều này phụ thuộc vào phiên bản Excel của bạn)

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: Câu trả lời của @ Graham (và có lẽ là những người khác) chung chung hơn câu trả lời của bạn: họ hỗ trợ hơn 4 ký tự trong tên cột. Và đó chính xác là lý do tại sao chúng lặp đi lặp lại.
bernard paulus

Trong thực tế, nếu họ sử dụng số nguyên không giới hạn và không phải ints, tên cột kết quả có thể dài tùy ý (ví dụ như trường hợp câu trả lời của con trăn)
bernard paulus

1
Nếu dữ liệu của tôi quá lớn đối với bảng tính 16.384 cột, tôi sẽ tự bắn vào đầu mình. Dù sao, Excel thậm chí không hỗ trợ tất cả các cột ba chữ cái có thể (nó bị cắt ở XFD để lại 1.894 cột). Ngay bây giờ dù sao đi nữa. Tôi sẽ cập nhật câu trả lời của tôi trong tương lai theo yêu cầu.
2023861

:) không biết điều đó! Nhận xét của tôi là về các tính chất lý thuyết của các thuật toán khác nhau.
bernard paulus

Đây có lẽ là giải pháp đơn giản và rõ ràng nhất.
Juan

8

Câu trả lời này có trong 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

Triển khai tương tự trong 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

Sau khi xem tất cả các Phiên bản được cung cấp ở đây, tôi đã quyết định tự làm một bản, sử dụng đệ quy.

Đây là phiên bản vb.net của tôi:

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

Trò chơi hơi muộn, nhưng đây là mã tôi sử dụng (trong 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
Bạn đã làm ngược lại những gì được yêu cầu, nhưng +1 cho lambda-fu của bạn.
Nurettin

IndexOflà khá chậm, tốt hơn hết là bạn nên sắp xếp lại ánh xạ ngược.
Vlad

5

Tôi muốn ném vào lớp tĩnh mà tôi sử dụng, để xen giữa chỉ số col và nhãn col. Tôi sử dụng một câu trả lời được chấp nhận sửa đổi cho Phương thức Cột của tôi

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

Sử dụng như thế này ...

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

4

nếu bạn chỉ muốn nó cho một công thức ô mà không có mã, thì đây là một công thức cho nó:

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

4

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

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

Nó không chính xác cơ sở 26, không có 0 trong hệ thống. Nếu có, 'Z' sẽ được theo sau bởi 'BA' chứ không phải 'AA'.


3

Trong perl, cho đầu vào 1 (A), 27 (AA), v.v.

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

Tinh chỉnh giải pháp ban đầu (trong 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

Đây là phiên bản 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

Giải pháp 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
Hãy thử chỉ số 26 và 27. Nó rất gần, nhưng tắt đi một.
Eric

value = Math.floor (giá trị / 26); nên là value = Math.ceil (value / 26) - 1;
Henry Liu

2

Các mã này của tôi để chuyển đổi số cụ thể (chỉ mục bắt đầu từ 1) sang Cột 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;
    }

Bài kiểm tra đơn vị của tôi:

    [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 để hiển thị tham chiếu ô tối đa trong các thử nghiệm của bạn (XFD) - bạn sẽ không tin việc tìm thông tin đó trên web khó đến mức nào.
hộp điều khiển

2

Mặc dù tôi đến trễ trò chơi, câu trả lời của Graham không phải là tối ưu. Đặc biệt, bạn không phải sử dụng modulo, gọi ToString()và áp dụng (int)diễn viên. Xem xét rằng trong hầu hết các trường hợp trong thế giới C #, bạn sẽ bắt đầu đánh số từ 0, đây là bản sửa đổi của tôi:

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

Một cách khác của VBA

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

1

Đây là triển khai siêu muộn của tôi trong PHP. Đây là đệ quy. Tôi đã viết nó ngay trước khi tôi tìm thấy bài viết này. Tôi muốn xem những người khác đã giải quyết vấn đề này chưa ...

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

Tôi đang cố gắng làm điều tương tự trong Java ... Tôi đã viết đoạn mã sau:

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

Bây giờ khi tôi chạy nó với cộtNumber = 29, nó sẽ cho tôi kết quả = "CA" (thay vì "AC") bất kỳ nhận xét nào tôi đang thiếu? Tôi biết tôi có thể đảo ngược nó bằng StringBuilder .... Nhưng nhìn vào câu trả lời của Graham, tôi hơi bối rối ....


Graham nói: columnName = Convert.ToChar(65 + modulo).ToString() + columnName(tức là giá trị + ColName). Hasan nói: columnName += val;(tức là giá trị ColName +)
mcalex

Bạn đang nối thêm nhân vật mới thay vì trả trước nó. Nên columnName = columnName + val.
Domenic D.

1

Phiên bản Ruby trùng hợp và thanh lịch :

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

Đây là câu hỏi mà tất cả những người khác cũng như Google chuyển hướng đến vì vậy tôi sẽ đăng bài này lên đây.

Nhiều câu trả lời trong số này là đúng nhưng quá cồng kềnh đối với các tình huống đơn giản như khi bạn không có hơn 26 cột. Nếu bạn có bất kỳ nghi ngờ nào về việc bạn có thể đi vào các cột hai ký tự hay không thì hãy bỏ qua câu trả lời này, nhưng nếu bạn chắc chắn rằng bạn sẽ không, thì bạn có thể làm điều đó đơn giản như trong 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, nếu bạn tự tin về những gì bạn đang vượt qua, bạn thậm chí có thể xóa xác thực và sử dụng nội tuyến này:

(char)('A' + index)

Điều này sẽ rất giống nhau trong nhiều ngôn ngữ để bạn có thể điều chỉnh nó khi cần thiết.

Một lần nữa, chỉ sử dụng điều này nếu bạn chắc chắn 100% rằng bạn sẽ không có hơn 26 cột .


1

Cảm ơn câu trả lời ở đây !! đã giúp tôi đưa ra các chức năng trợ giúp này để tương tác với API Google Sheets mà tôi đang làm việc trong Elixir / Phoenix

đây là những gì tôi nghĩ ra (có thể sử dụng một số xác nhận bổ sung và xử lý lỗi)

Trong 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

Và hàm nghịch đảo:

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

Và một số bài kiểm tra:

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
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.