วิธีแปลงหมายเลขคอลัมน์ (เช่น 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 Library General Public License (LGPL) การใช้ EPPlus คุณสามารถรับสตริงคอลัมน์ได้อย่างง่ายดาย
Tony_KiloPapaMikeGolf

โปรดทราบว่าข้อ จำกัด ของแถวและคอลัมน์นั้นขึ้นอยู่กับรูปแบบไฟล์มากกว่ารุ่น Excel และอาจแตกต่างกันสำหรับแต่ละเวิร์กบุ๊ก พวกเขาสามารถเปลี่ยนแปลงแม้กระทั่งสำหรับสมุดงานเดียวกันหากบันทึกเป็นรูปแบบเก่าหรือใหม่กว่า
Slai

คำตอบ:


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 เป็นคอลัมน์หมายเลข 1 ฉันต้องทำการเปลี่ยนแปลงอย่างรวดเร็วเพื่อบัญชีสำหรับระบบของฉันโดยใช้คอลัมน์ A เป็นคอลัมน์หมายเลข 0 ฉันเปลี่ยนการจ่ายเงินปันผลบรรทัดเป็น int เงินปันผล = columnNumber + 1; Keith
Keith Sirmons

14
@Jduv StringBuilderก็พยายามออกมาใช้ ใช้เวลาประมาณสองเท่า มันเป็นสตริงที่สั้นมาก (สูงสุด 3 ตัวอักษร - Excel 2010 ขึ้นอยู่กับคอลัมน์ XFD) ดังนั้นการต่อกันของสตริงสูงสุด 2 รายการ (ฉันใช้การวนซ้ำ 100 ครั้งในการแปลจำนวนเต็ม 1 ถึง 16384 เช่นคอลัมน์ Excel A ถึง XFD เป็นการทดสอบ)
Graham

18
เพื่อความเข้าใจที่ดีขึ้นฉันจะแทนที่ 65 ด้วย 'A'
Stef Heyenrath

11
ฉันคิดว่ามันจะดีกว่าถ้าใช้ 'A' แทน 65 และ 26 สามารถประเมินเป็น ('Z' - 'A' + 1) ตัวอย่างเช่น: const int AlphabetLength = 'Z' - 'A' + 1;
เดนิส Gladkiy

5
แม้ว่าฉันจะเล่นเกมช้า แต่รหัสก็ยังห่างไกลจากความเหมาะสมโดยเฉพาะอย่างยิ่งคุณไม่จำเป็นต้องใช้การmoduloโทรToString()และสมัคร(int)นักแสดง พิจารณาว่าในกรณีส่วนใหญ่ในโลก C # คุณจะเริ่มนับจาก 0 นี่คือการแก้ไขของฉัน: <! - language: c # -> สตริงคงที่สาธารณะ GetColumnName (ดัชนี int) // zero-based {const ไบต์ฐาน = 'Z '-' A '+ 1; string name = String.Empty; ทำ {name = Convert.ToChar ('A' + ดัชนี% BASE) + ชื่อ index = index / BASE - 1; } while (ดัชนี> = 0); ชื่อส่งคืน; }
Herman Kan

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
ตัวอย่าง: = SUBSTITUTE (TEXT (ADDRESS (1,1000,4), ""), "1", "")
Dolph

ใช่ฉันใช้ Excel ในตำแหน่งที่ตั้งที่; ใช้แทนที่การขัดแย้งของฟังก์ชันใน Excel ขอบคุณที่ชี้นำสิ่งนี้
vzczc

2
ฉันทำสิ่งนี้โดยไม่มีฟังก์ชั่น TEXT วัตถุประสงค์ของฟังก์ชั่น TEXT คืออะไร?
dayuloli

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!
Tim-Erwin

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 คุณสามารถทำได้ด้วยตัวอักษรของตัวอักษร

Space: ......................... 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 + ….

สมมติว่าคุณต้องการค้นหาจำนวนสถานะทั้งหมดในช่องว่าง N แรก สูตรในการทำเช่นนี้คือ A = (a) (a ^ N - 1) / (a-1) สิ่งนี้มีความสำคัญเนื่องจากเราต้องการค้นหาพื้นที่ N ที่สอดคล้องกับดัชนี K ของเราถ้าฉันต้องการหาที่ K อยู่ในระบบจำนวนฉันต้องแทนที่ A ด้วย K และแก้หา N วิธีแก้ปัญหาคือ N = log { ฐาน a} (A (a-1) / a +1) ถ้าฉันใช้ตัวอย่างของ a = 10 และ K = 192 ฉันรู้ว่า N = 2.23804 … นี่บอกฉันว่า K อยู่ที่จุดเริ่มต้นของช่องว่างที่สามเนื่องจากมันใหญ่กว่าสองเล็กน้อย

ขั้นตอนต่อไปคือการค้นหาว่าเราอยู่ไกลแค่ไหนในพื้นที่ปัจจุบัน หากต้องการค้นหาสิ่งนี้ให้ลบออกจาก K a ที่สร้างโดยใช้ชั้นของ N ในตัวอย่างนี้พื้นของ N คือสอง ดังนั้น A = (10) (10 ^ 2 - 1) / (10-1) = 110 ตามที่คาดไว้เมื่อคุณรวมสถานะของช่องว่างสองช่องแรก จำเป็นต้องลบออกจาก K เนื่องจาก 110 รัฐแรกเหล่านี้จะถูกนำมาใช้ในสองช่องว่างแรกแล้ว สิ่งนี้ทำให้เรามี 82 รัฐ ดังนั้นในระบบจำนวนนี้การแทนค่า 192 ในฐาน 10 คือ 082

รหัส C # ที่ใช้ดัชนีฐานเป็นศูนย์คือ

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

// โพสต์เก่า

วิธีการแก้ปัญหา zero-based ใน 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.Empty;
ประเภทไม่ระบุชื่อ

ใช่คำอธิบายที่ดีมาก แต่คุณสามารถเพียงแค่ระบุว่ามันไม่ได้เป็นฐาน 27 เช่นกัน? คำอธิบายของคุณจะแสดงสิ่งนี้เมื่อศึกษา แต่การกล่าวถึงอย่างรวดเร็วที่ด้านบนอาจช่วยคนอื่นไม่กี่ครั้ง
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;

Update : ความคิดเห็นของPeterถูกต้อง นั่นคือสิ่งที่ฉันได้รับจากการเขียนโค้ดในเบราว์เซอร์ :-) วิธีการแก้ปัญหาของฉันไม่ได้รวบรวมมันก็หายไปตัวอักษรซ้ายสุดและมันก็สร้างสตริงในลำดับที่กลับกัน - ทั้งหมดตอนนี้ได้รับการแก้ไข

ขั้นตอนวิธีจะทำการแปลงจำนวนจากฐาน 10 เป็นฐาน 26

อัปเดต 2 : Joel Coehoornถูกต้อง - โค้ดด้านบนจะคืนค่า AB เป็น 27 ถ้าเป็นฐาน 26 จริง AA จะเท่ากับ A และ 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
Joel Coehoorn

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 ดังนั้นโซลูชันแบบเรียกซ้ำจึงง่ายกว่ามาก
Joel Coehoorn

รูทีนนี้ใช้งานไม่ได้จริง ตัวอย่างเช่น GetStandardExcelColumnName (26) return @ 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.
Mulli

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: @ คำตอบของ Graham (และอาจเป็นคำอื่น ๆ ) นั้นมีความกว้างมากกว่าของคุณ: พวกมันรองรับอักขระมากกว่า 4 ตัวในชื่อคอลัมน์ และนั่นเป็นเหตุผลว่าทำไมพวกเขาซ้ำ
เบอร์นาร์ดพอลลัส

ในความเป็นจริงถ้าพวกเขาใช้จำนวนเต็มไม่ จำกัด และไม่ints ชื่อคอลัมน์ที่เกิดขึ้นอาจจะเป็นพลยาว (เป็นกรณีของคำตอบหลามตัวอย่างเช่น)
เบอร์นาร์ดพอลลัส

1
หากข้อมูลของฉันมีขนาดใหญ่เกินไปสำหรับสเปรดชีต 16,384 คอลัมน์ฉันจะยิงหัวตัวเอง อย่างไรก็ตาม Excel ไม่สนับสนุนคอลัมน์สามตัวอักษรที่เป็นไปได้ทั้งหมด (มันตัดที่ XFD ที่เหลือ 1,894 คอลัมน์) ตอนนี้ยังไงก็ตาม ฉันจะอัปเดตคำตอบของฉันในอนาคตตามที่ต้องการ
user2023861

:) ไม่รู้ว่า! ความคิดเห็นของฉันเป็นคุณสมบัติทางทฤษฎีของอัลกอริทึมที่แตกต่างกัน
เบอร์นาร์ดพอลลัส

อันนี้น่าจะเป็นทางออกที่ง่ายและชัดเจนที่สุด
Juan

8

คำตอบนี้อยู่ในจาวาสคริปต์:

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

implementaion เดียวกันใน 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 สำหรับแลมบ์ดาฟูของคุณ
nurettin

IndexOfค่อนข้างช้าคุณควรคาดคะเนการทำแผนที่ย้อนกลับดีกว่า
วลาด

5

ฉันต้องการที่จะโยนในระดับคงที่ของฉันที่ฉันใช้สำหรับการสอดแทรกระหว่างดัชนีสีและฉลากสี ฉันใช้คำตอบที่ได้รับการยอมรับสำหรับวิธีการแก้ไขแบบคอลัมน์ของฉัน

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

มันไม่ได้เป็นฐานที่ 26 แน่นอนว่าไม่มี 0 ในระบบ หากมี 'Z' จะตามด้วย 'BA' ไม่ใช่ 'AA'


3

ใน perl สำหรับอินพุต 1 (A), 27 (AA) ฯลฯ

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

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

นี่คือเวอร์ชัน 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;
    }

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 มันใกล้มาก แต่ปิดทีละราย
Eric

ค่า = Math.floor (ค่า / 26); ควรเป็น value = Math.ceil (value / 26) - 1;
Henry Liu

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) - คุณจะไม่เชื่อเลยว่าการค้นหาข้อมูลนั้นบนเว็บเป็นเรื่องยาก
controlbox

2

แม้ว่าฉันจะเล่นเกมช้า แต่คำตอบของเกรแฮมก็ยังห่างไกลจากความเหมาะสม โดยเฉพาะอย่างยิ่งคุณไม่จำเป็นต้องใช้การmoduloโทรToString()และสมัครการ(int)ส่ง พิจารณาว่าในกรณีส่วนใหญ่ในโลก C # คุณจะเริ่มนับจาก 0 นี่คือการแก้ไขของฉัน:

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

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

    return name;
}

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 .... แต่ดูคำตอบของเกรแฮมฉันสับสนเล็กน้อย ....


Graham พูดว่า: columnName = Convert.ToChar(65 + modulo).ToString() + columnName(เช่นค่า + ColName) Hasan พูดว่า: columnName += val;(เช่น ColName + value)
mcalex

คุณกำลังต่อท้ายอักขระใหม่แทนการเติม columnName = columnName + valควรจะเป็น
Domenic D.

1

รุ่น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);
}

Heck หากคุณมั่นใจในสิ่งที่คุณส่งผ่านคุณสามารถลบการตรวจสอบและใช้ inline นี้:

(char)('A' + index)

สิ่งนี้จะคล้ายกันมากในหลายภาษาเพื่อให้คุณสามารถปรับได้ตามต้องการ

อีกครั้งเพียงใช้นี้หากคุณกำลัง 100% แน่ใจว่าคุณจะไม่ได้มีมากกว่า 26 คอลัมน์


1

ขอบคุณสำหรับคำตอบที่นี่ !! ช่วยฉันคิดหาฟังก์ชั่นตัวช่วยเหล่านี้สำหรับการโต้ตอบกับ Google ชีต API ที่ฉันทำงานใน Elixir / Phoenix

นี่คือสิ่งที่ฉันมาด้วย (อาจจะใช้การตรวจสอบและการจัดการข้อผิดพลาดพิเศษบางอย่าง)

ใน 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

และฟังก์ชันผกผัน:

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
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.