열 번호 (예 : 127)를 Excel 열 (예 : AA)로 변환하는 방법


474

자동화를 사용하여 Excel에서 직접 값을 가져 오지 않고 C #에서 숫자를 Excel 열 이름으로 변환하는 방법은 무엇입니까?

Excel 2007의 가능한 범위는 1-16384이며 지원되는 열 수입니다. 결과 값은 A, AA, AAA 등 엑셀 열 이름 형식이어야합니다.


1
사용 가능한 열 수에 제한이 있다는 것을 잊지 마십시오. 예 : * Excel 2003 (v11)은 IV, 2 ^ 8 또는 256 열로 증가합니다). * Excel 2007 (v12)은 XFD, 2 ^ 14 또는 16384 열로 올라갑니다.
Unsliced


이 질문은 C #과 excel로 태그됩니다. 우리는 2016 년에 살고 EPPLUS 가 있기 때문에이 질문을 구식으로 표시 합니다. 서버에서 고급 Excel 스프레드 시트를 작성하기 위해 일반적으로 사용되는 C # 라이브러리입니다. GNU 라이브러리 일반 공중 사용 허가서 (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가 columnNumber 1 인 것으로 가정합니다. 열 A를 columnNumber 0으로 사용하여 시스템을 신속하게 변경해야했습니다. Keith
Keith Sirmons

14
@Jduv는 방금 사용하여 시도했습니다 StringBuilder. 약 두 배의 시간이 걸립니다. 매우 짧은 문자열 (최대 3 자-Excel 2010은 XFD 열까지)이므로 최대 2 개의 문자열 연결입니다. (테스트로 정수 1에서 16384, 즉 Excel 열 A에서 XFD로 변환하는 100 회 반복 사용).
Graham

18
이해를 돕기 위해 65를 'A'로 대체합니다
Stef Heyenrath

11
65 대신 'A'를 사용하는 것이 좋습니다. 26은 ( 'Z'- 'A'+ 1)로 평가할 수 있습니다. 예를 들면 다음과 같습니다. const int AlphabetLength = 'Z'- 'A'+ 1;
Denis Gladkiy

5
게임에 늦었지만 코드가 최적이 아닙니다. 특히 modulo, 호출 ToString()(int)캐스트 를 사용할 필요는 없습니다 . C # 세계에서 대부분의 경우 0부터 번호 매기기를 시작한다는 것을 고려할 때 여기에 내 개정이 있습니다 : <!-language : c #-> public static string GetColumnName (int index) // 0부터 시작하는 {const byte BASE = 'Z '-'A '+ 1; 문자열 이름 = String.Empty; do {name = Convert.ToChar ( 'A'+ index % BASE) + 이름; 인덱스 = 인덱스 / BASE-1; } while (인덱스> = 0); 반환 이름; }
허먼 칸

63

VBA없이 Excel 에서이 작업을 수행 해야하는 사람은 다음과 같습니다.

=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

죄송합니다. C # 대신 Python이지만 최소한 결과는 정확합니다.

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

예, downVoted, 질문이 C # 일 때 Python을 게시하지 마십시오. 그리고 더 많은 사람들이 이것을해야합니다.
KyloRen

1
질문의 제목이 C #을 의미하지는 않으므로 C #을 실행하지 않는 많은 사람들이 여기에 올 수 있습니다. 따라서 파이썬에서 공유해 주셔서 감사합니다!
Tim-Erwin

20

AAZ와 같은 Excel 열 주소에서 정수로, 정수에서 Excel로 두 가지 방법으로 변환해야 할 수 있습니다. 아래의 두 가지 방법이 바로 그렇게 할 것입니다. 1 기반 인덱싱을 가정하고 "배열"의 첫 번째 요소는 요소 번호 1입니다. 여기에 크기 제한이 없으므로 ERROR와 같은 주소를 사용할 수 있으며 열 번호는 2613824입니다.

public static string ColumnAdress(int col)
{
  if (col <= 26) { 
    return Convert.ToChar(col + 64).ToString();
  }
  int div = col / 26;
  int mod = col % 26;
  if (mod == 0) {mod = 26;div--;}
  return ColumnAdress(div) + ColumnAdress(mod);
}

public static int ColumnNumber(string colAdress)
{
  int[] digits = new int[colAdress.Length];
  for (int i = 0; i < colAdress.Length; ++i)
  {
    digits[i] = Convert.ToInt32(colAdress[i]) - 64;
  }
  int mul=1;int res=0;
  for (int pos = digits.Length - 1; pos >= 0; --pos)
  {
    res += digits[pos] * mul;
    mul *= 26;
  }
  return res;
}

13

첫 번째 게시물에서 오류가 발견되어 앉아서 ​​수학을하기로 결정했습니다. 내가 찾은 것은 다른 사람이 게시 한 것처럼 Excel 열을 식별하는 데 사용되는 숫자 시스템이 기본 26 시스템이 아니라는 것입니다. 밑줄 10에서 다음을 고려하십시오. 알파벳 문자로도이를 수행 할 수 있습니다.

공간 : ......................... S1, S2, S3 : S1, S2, S3
............ ........................ 0, 00, 000 : .. A, AA, AAA
............. ....................... 1, 01, 001 : .. B, AB, AAB
.............. ............... ..., ..., ... .. ... ... ...
... ... ... ... ... ..................... 9, 99, 999 : .. Z, ZZ, ZZZ
공간의 총 상태 : 10, 100, 1000 : 26, 676, 17576
총 상태 : ............... 1110 ................ 18278

Excel은 base 26을 사용하여 개별 알파벳 공간의 열에 번호를 매 깁니다. 일반적으로 상태 공간 진행은 a, a ^ 2, a ^ 3,… 일부 a의 경우 총 상태 수는 + a입니다. ^ 2 + a ^ 3 +….

첫 번째 N 공간에서 총 상태 수 A를 찾고 싶다고 가정하십시오. 그렇게하는 공식은 A = (a) (a ^ N-1) / (a-1)입니다. 인덱스 K에 해당하는 공간 N을 찾아야하기 때문에 중요합니다. 숫자 시스템에서 K가 어디에 있는지 알아 내려면 A를 K로 바꾸고 N을 풀어야합니다. 해결책은 N = log { 기본 a} (A (a-1) / a +1). a = 10 및 K = 192의 예를 사용하면 N = 2.23804… 이것은 K가 두 번째보다 약간 크기 때문에 세 번째 공간의 시작 부분에 있다는 것을 말해줍니다.

다음 단계는 현재 공간에서 얼마나 멀리 있는지 정확히 찾는 것입니다. 이를 찾으려면 N의 바닥을 사용하여 생성 된 A를 K에서 빼십시오.이 예에서 N의 바닥은 2입니다. 따라서 처음 두 공백의 상태를 결합 할 때 예상되는대로 A = (10) (10 ^ 2 – 1) / (10-1) = 110입니다. 처음 110 개 주가 처음 두 공간에서 이미 설명 되었기 때문에 K에서 빼야합니다. 이로 인해 82 개 주가 생깁니다. 따라서이 수 체계에서 밑 10의 192는 082입니다.

기본 인덱스 0을 사용하는 C # 코드는

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

// 오래된 게시물

C #의 제로 기반 솔루션.

    private string ExcelColumnIndexToName(int Index)
    {
        string range = "";
        if (Index < 0 ) return range;
        for(int i=1;Index + i > 0;i=0)
        {
            range = ((char)(65 + Index % 26)).ToString() + range;
            Index /= 26;
        }
        if (range.Length > 1) range = ((char)((int)range[0] - 1)).ToString() + range.Substring(1);
        return range;
    }

왜 그런지 모르겠지만이 솔루션을 좋아합니다. 프로그래머 수준의 로직을 쉽게 읽을 수있는 코드를 쉽게 읽을 수있는 코드는 없습니다. 한 가지, C #에서 빈 문자열을 문자열 범위 = 문자열로 지정하는 것이 가장 좋습니다.
익명 유형

예, 아주 좋은 설명입니다. 하지만 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;

업데이트 : Peter 의 의견이 맞습니다. 그것이 브라우저에서 코드를 작성하기 위해 얻는 것입니다. :-) 내 솔루션이 컴파일되지 않았으며 가장 왼쪽에있는 문자가 누락되었으며 문자열을 역순으로 작성했습니다. 이제 모두 수정되었습니다.

버그는 제쳐두고, 알고리즘은 기본적으로 숫자를 밑 10에서 밑 26으로 변환합니다.

업데이트 2 : Joel Coehoorn 이 옳습니다. 위의 코드는 27에 대해 AB를 반환합니다. 실제 밑수 26의 숫자 인 경우 AA는 A와 같고 Z 다음의 숫자는 BA입니다.

int nCol = 127;
string sChars = "0ABCDEFGHIJKLMNOPQRSTUVWXYZ";
string sCol = "";
while (nCol > 26)
{
    int nChar = nCol % 26;
    if (nChar == 0)
        nChar = 26;
    nCol = (nCol - nChar) / 26;
    sCol = sChars[nChar] + sCol;
}
if (nCol != 0)
    sCol = sChars[nCol] + sCol;

코드가 컴파일되지 않습니다 (sCol이 초기화되지 않음). 그렇다면 올바른 대답을 제공하지 않습니다.
Peter

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는 08:08

1
기본 26이 아니라 재귀 솔루션이 훨씬 간단합니다.
Joel Coehoorn

이 루틴은 실제로 작동하지 않습니다. 예를 들어 GetStandardExcelColumnName (26)은 @을 반환합니다. GetStandardExcelColumnName (52)는 B @을 반환합니다.
sgmoore

1
"가장 단순한"솔루션과 달리 가장 명확합니다.
익명 유형

9

여기에있는 모든 대답이 필요한 것보다 훨씬 복잡해 보이기 때문에 재귀를 사용하여 간단한 두 줄의 C # 구현을 던지십시오.

/// <summary>
/// Gets the column letter(s) corresponding to the given column number.
/// </summary>
/// <param name="column">The one-based column index. Must be greater than zero.</param>
/// <returns>The desired column letter, or an empty string if the column number was invalid.</returns>
public static string GetColumnLetter(int column) {
    if (column < 1) return String.Empty;
    return GetColumnLetter((column - 1) / 26) + (char)('A' + (column - 1) % 26);
}

8

.. 그리고 PHP로 변환 :

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

ord('A')65 대신 사용하십시오 .
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
참고 : @Graham의 대답 (그리고 아마도 다른 것)은 당신보다 더 일반적입니다 : 그들은 열 이름에서 4 + 문자를 지원합니다. 그리고 그것이 정확하게 반복되는 이유입니다.
bernard paulus

사실, 그들이 무제한 정수를 사용하고 ints가 아닌 경우, 결과로 나오는 열 이름은 임의로 길어질 수 있습니다 (예를 들어, 파이썬 답변의 경우)
bernard paulus

1
16,384 열의 스프레드 시트에 비해 데이터가 너무 큰 경우 직접 처리 할 것입니다. 어쨌든 Excel은 가능한 3 문자 열을 모두 지원하지 않습니다 (1,894 열을 제외하고 XFD에서 잘림). 어쨌든 지금. 필요한 경우 나중에 답변을 업데이트하겠습니다.
user2023861

:) 그것을 몰랐다! 내 의견은 다른 알고리즘의 이론적 속성에 관한 것이었다.
bernard paulus

이것은 아마도 가장 단순하고 명확한 솔루션 일 것입니다.
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

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 February

IndexOf매우 느리다면 리버스 매핑을 미리 계산하는 것이 좋습니다.
Vlad

5

col 인덱스와 col Label 간의 상호 작용을 위해 사용하는 정적 클래스를 던지고 싶었습니다. ColumnLabel 메서드에 대해 수정 된 수락 된 답변을 사용합니다.

public static class Extensions
{
    public static string ColumnLabel(this int col)
    {
        var dividend = col;
        var columnLabel = string.Empty;
        int modulo;

        while (dividend > 0)
        {
            modulo = (dividend - 1) % 26;
            columnLabel = Convert.ToChar(65 + modulo).ToString() + columnLabel;
            dividend = (int)((dividend - modulo) / 26);
        } 

        return columnLabel;
    }
    public static int ColumnIndex(this string colLabel)
    {
        // "AD" (1 * 26^1) + (4 * 26^0) ...
        var colIndex = 0;
        for(int ind = 0, pow = colLabel.Count()-1; ind < colLabel.Count(); ++ind, --pow)
        {
            var cVal = Convert.ToInt32(colLabel[ind]) - 64; //col A is index 1
            colIndex += cVal * ((int)Math.Pow(26, pow));
        }
        return colIndex;
    }
}

이것을 사용하십시오 ...

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

4

코드가없는 셀 수식에 대해 원하는 경우 수식이 있습니다.

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

4

델파이 (파스칼)에서 :

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'다음에 'AA'가 아닌 'BA'가옵니다.


3

펄에서 1 (A), 27 (AA) 등의 입력

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

2

원래 솔루션을 다듬기 (C #에서) :

public static class ExcelHelper
{
    private static Dictionary<UInt16, String> l_DictionaryOfColumns;

    public static ExcelHelper() {
        l_DictionaryOfColumns = new Dictionary<ushort, string>(256);
    }

    public static String GetExcelColumnName(UInt16 l_Column)
    {
        UInt16 l_ColumnCopy = l_Column;
        String l_Chars = "0ABCDEFGHIJKLMNOPQRSTUVWXYZ";
        String l_rVal = "";
        UInt16 l_Char;


        if (l_DictionaryOfColumns.ContainsKey(l_Column) == true)
        {
            l_rVal = l_DictionaryOfColumns[l_Column];
        }
        else
        {
            while (l_ColumnCopy > 26)
            {
                l_Char = l_ColumnCopy % 26;
                if (l_Char == 0)
                    l_Char = 26;

                l_ColumnCopy = (l_ColumnCopy - l_Char) / 26;
                l_rVal = l_Chars[l_Char] + l_rVal;
            }
            if (l_ColumnCopy != 0)
                l_rVal = l_Chars[l_ColumnCopy] + l_rVal;

            l_DictionaryOfColumns.ContainsKey(l_Column) = l_rVal;
        }

        return l_rVal;
    }
}

2

액션 스크립트 버전은 다음과 같습니다.

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

자바 스크립트 솔루션

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

테스트 (XFD)에서 최대 셀 참조가 무엇인지 보여주는 +1-웹에서 해당 정보를 찾는 것이 얼마나 어려운지 믿지 않을 것입니다.
controlbox

2

비록 게임에 늦었지만 Graham의 대답 은 최적이 아닙니다. 특히, 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). 하산의 말 : columnName += val;(즉 ColName + value)
mcalex

새 캐릭터를 추가하는 대신 추가합니다. 이어야 columnName = columnName + val합니다.
Domenic D.

1

화려하고 우아한 루비 버전 :

def col_name(col_idx)
    name = ""
    while col_idx>0
        mod     = (col_idx-1)%26
        name    = (65+mod).chr + name
        col_idx = ((col_idx-mod)/26).to_i
    end
    name
end

1

이것은 Google뿐만 아니라 다른 모든 사람들에게 질문으로 여기에 게시하고 있습니다.

26 개가 넘는 열이없는 경우와 같은 간단한 상황에서는 이러한 정답이 정확하지만 너무 번거 롭습니다. 이중 문자 열로 들어갈 수 있는지 의심 스럽다면이 대답을 무시하십시오.하지만 확실하지 않으면 C #에서 다음과 같이 간단하게 수행 할 수 있습니다.

public static char ColIndexToLetter(short index)
{
    if (index < 0 || index > 25) throw new ArgumentException("Index must be between 0 and 25.");
    return (char)('A' + index);
}

당신이 전달하는 것에 확신이 있다면 검증을 제거 하고이 인라인을 사용할 수도 있습니다.

(char)('A' + index)

이것은 많은 언어에서 매우 유사하므로 필요에 따라 조정할 수 있습니다.

다시 말하지만, 열이 26 개를 초과하지 않을 것이라고 100 % 확신하는 경우에만 사용하십시오 .


1

답변을 주셔서 감사합니다! Elixir / Phoenix에서 작업중인 Google Sheets API와의 상호 작용을 위해 이러한 도우미 기능을 생각해 냈습니다.

여기에 내가 생각해 낸 것이 있습니다 (아마도 추가 유효성 검사 및 오류 처리를 사용할 수 있음)

엘릭서 :

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.