programing

OpenXML C#을 사용하여 Excel에서 셀의 열 인덱스 가져오기

testmans 2023. 7. 9. 10:36
반응형

OpenXML C#을 사용하여 Excel에서 셀의 열 인덱스 가져오기

저는 지금 한참을 둘러보고 있는데 어떻게 해야 할지 모르겠어요.저는 OpenXML을 사용하여 읽고 있는 엑셀 시트를 가지고 있습니다. 일반적인 것은 행을 반복하고 셀을 반복해서 값을 얻는 것입니다. 괜찮습니다.그러나 값과 함께 셀의 위치가 필요합니다. 셀의 위치는 (행 색인, 열 색인) 형식입니다.행 인덱스를 얻었지만 열 인덱스를 얻지 못했습니다.

저는 사실 이것이 쉬울 거라고 생각했지만 분명히 그렇지 않습니다.

스키마에서 빈 셀을 생략할 수 있기 때문에 이 작업은 상상보다 약간 까다롭습니다.

인덱스를 가져오려면 참조를 형식으로 제공하는 속성을 가진 개체를 사용할 수 있습니다.A1,B1기타. 해당 참조를 사용하여 열 번호를 추출할 수 있습니다.

에서는 엑마서지만겠, 에셀시아.A = 1,B = 2까지 등Z = 26서 셀 에는 세가접두어있지서점에는포▁are서에가 붙습니다.A주다, 주다, 주다, 주다, 주다, 주다, 주다, 주다, 주다,.AA = 27,AB = 28로 ①의 에는 ②: ③의 경우가 있습니다.AA 번째 1파운드A. "은 "이고, 두 번째 배초입 26다니즉의값다이입니초이고의값▁"▁the, "26"은 "26"의 ▁of▁i▁has,다이값입니초고▁whilst의즉;worth26▁26""▁"배▁a▁26▁is▁second다▁the▁value▁second▁26▁times"A값은 "값" 1이며, 총 27입니다.

열 인덱스를 계산하려면 문자를 반대로 사용한 다음 첫 번째 문자의 값을 가져와 실행 합계에 추가할 수 있습니다.그런 다음 두 번째 문자의 값을 취하여 26을 곱하여 첫 번째 숫자에 합계를 더합니다.세 번째는 26을 곱하고 두 번 더하면 네 번째는 26을 곱하면 263을 곱하면 됩니다.

에 대해서는ABC다음을 수행할 수 있습니다.

C = 3
B = 2 * 26 = 52
A = 1 * 26 *26 = 676
3 + 52 + 676 = 731

C#에서 다음이 작동합니다.

private static int? GetColumnIndex(string cellReference)
{
    if (string.IsNullOrEmpty(cellReference))
    {
        return null;
    }

    //remove digits
    string columnReference = Regex.Replace(cellReference.ToUpper(), @"[\d]", string.Empty);

    int columnNumber = -1;
    int mulitplier = 1;

    //working from the end of the letters take the ASCII code less 64 (so A = 1, B =2...etc)
    //then multiply that number by our multiplier (which starts at 1)
    //multiply our multiplier by 26 as there are 26 letters
    foreach (char c in columnReference.ToCharArray().Reverse())
    {
        columnNumber += mulitplier * ((int)c - 64);

        mulitplier = mulitplier * 26;
    }

    //the result is zero based so return columnnumber + 1 for a 1 based answer
    //this will match Excel's COLUMN function
    return columnNumber + 1;
}

로 고는 다음과 .CellReferenceXML에 있을 것이라고 보장되지는 않습니다(비록 XML에 없는 것을 본 적은 없지만).다음과 같은 경우.CellReference입니다. 셀에 됩니다. 셀이 가장 왼쪽에 있는 셀에 배치됩니다.RowIndex또한 사양에서 필수 사항이 아니므로 셀이 사용 가능한 가장 높은 행에 배치되는 경우에도 생략할 수 있습니다.자세한 내용은 이 질문에서 확인할 수 있습니다.@BCdotWEB의 답은 다음과 같은 경우에 올바른 접근법입니다.CellReference이라null.

작은 것은 아름답습니다.

int ColumnIndex(string reference)
{
  int ci=0;
  reference=reference.ToUpper();
  for (int ix = 0; ix < reference.Length && reference[ix] >= 'A';ix++ ) 
       ci = (ci * 26) + ((int)reference[ix] - 64);
  return ci;
}
    public static void CellReferenceToIndex(string reference, out int row_index, out int col_index)
    {
        row_index = 0;
        col_index = 0;

        foreach(char c in reference)
        {
            if (c >= '0' && c <= '9')
            {
                row_index = row_index * 10 + (c - '0');
            }
            if (c >= 'A' && c <= 'Z')
            {
                col_index = col_index * ('Z' - 'A' + 1) + (c - 'A' + 1);
            }
        }
    }
    [TestCase( 1, 0, "A1" )]
    [TestCase( 2, 25, "Z2" )]
    [TestCase( 2, 38, "AM2" )]
    [TestCase( 2, (26 * 4) + 1, "DB2" )]
    [TestCase( 2, (26 * 26 * 26 * 18) + (26 * 26 * 1) + (26 * 26 * 1) + ( 26 * 1 ) + 2, "RBAC2" )]
    public void CanGetCorrectCellReference( int row, int column, string expected )
        => GetCellReference( (uint)row, (uint)column ).Value.ShouldEqual( expected );

    public static StringValue GetCellReference( uint row, uint column ) =>
        new StringValue($"{GetColumnName("",column)}{row}");

    static string GetColumnName( string prefix, uint column ) => 
        column < 26 ? $"{prefix}{(char)( 65 + column)}" : 
        GetColumnName( GetColumnName( prefix, ( column - column % 26 ) / 26 - 1 ), column % 26 );

답변을 시작하기 위해 먼저 이것을 살펴보시기를 요청합니다.

이미 설명했듯이 행과 열을 추출하는 쉬운 방법은 없습니다.가장 가까운 것은 다음의 추출입니다.CellReference의 형태를 가진 세포의A1,B2사실은COLUMN_ROW서식을 정하다

에서 행 및 열을 추출할 수 있습니다.CellReference예, 이 경우 확인해야 하는 방법을 구현해야 합니다.char타고char숫자와 문자열을 확인합니다.

당신이 가지고 있다고 가정해 봅시다.A11그런 다음 인덱스 열이 필요할 때 추출해야 합니다.A이는column 1예, 그렇게 쉽지는 않지만 셀을 통해 스캔/반복할 때 단순히 열 수를 세도록 선택하지 않는 한 유일한 방법입니다.

같은 일을 하는 이 질문들의 답을 다시 한번 보세요.

    Row row = worksheetPart.Worksheet.GetFirstChild<SheetData>().Elements<Row>().FirstOrDefault();
   var totalnumberOfColumns = 0;
    if (row != null)
        {
            var spans = row.Spans != null ? row.Spans.InnerText : "";
                if (spans != String.Empty)
                        {
                            //spans.Split(':')[1];
                            string[] columns = spans.Split(':');
                            startcolumnInuse = int.Parse(columns[0]);
                            endColumnInUse = int.Parse(columns[1]);
                            totalnumberOfColumns = int.Parse(columns[1]);
                        }
        }

존재/사용된 총 열 수를 찾기 위한 것입니다. enter image description here

제 시나리오에서는 열 이름(셀 번호 없음)만 처리하면 되었고 LINQ를 사용했습니다. 이는 참조용으로 여기에 넣을 가치가 있다고 생각했습니다.

const int AsciiTrim = 'A' - 1; //64
const int LastChar = 'Z' - AsciiTrim; //26

var colIndex = columnName
    .Reverse()
    .Select(ch => ch - AsciiTrim)
    .Select((ch, i) => ch * Math.Pow(LastChar, i))
    .Sum()
    - 1; //make zero-index based

되돌리고 전체 코드와 테스트를 보려면 다음 요점을 참조하십시오.

@petelids 답변에서 GetColumnIndex 함수가 약간 수정되었습니다.결과는 0 기반 인덱스가 됩니다.필요한 경우 1 기반 인덱스에 1을 추가합니다.

private static int CellReferenceToIndex(string reference)
{
    foreach (char ch in reference)
    {
        if (Char.IsLetter(ch))
        {
            int value = (int)ch - (int)'A';
            index = (index == 0) ? value : ((index + 1) * 26) + value;
        }
        else
            return index;
    }
    return index;
}
private double CellReferenceToIndex(Cell cell)
    {
        // if Cell is ABC4 => position is
        // = [Aindx * (26^2)] + [BIndx * (27^1)] + [CIndx * (27^0)]
        // = [1     * (26^2)] + [2     * (27^1)] + [3     * (27^0)]

        double index = 0;
        char [] reference = cell.CellReference.ToString().ToUpper().Reverse().ToArray();
        int letterPosition = 0;
       
        foreach (char ch in reference)
        {
            if (char.IsLetter(ch))
            {
                int value = (ch - 'A') + 1; // so A is 1 not 0 
                index += value * Math.Pow(26, letterPosition++);
            }
        }
        return index;
    }

이 오래된 질문에 새로운 접근 방식을 추가하기 위해, 저는 이것을 행에 있는 셀에 대한 열 인덱스를 가져오는 빠른 방법으로 사용합니다(OP가 나타내는 것처럼 시트 데이터의 행에 있는 셀을 반복하고 있다고 가정).

열거 가능하기 전의 요소를 사용하여 현재 루프하고 있는 셀보다 먼저 셀을 셀 수 있습니다. 이 카운트는 1 기반이고 요소 IE 숫자는 0 기반이므로, 카운트를 사용하면 현재 사용 중인 셀의 열 인덱스(기본적으로 이전 요소 + 1 = 현재 셀의 열 인덱스)를 얻을 수 있습니다.

그래서, 이런 것들이...

            For Each r In sht.Elements(Of Row)
                For Each c In sht.Elements(Of Row).ElementAt(r.RowIndex).Elements(Of Cell)
                    Dim iColumnIndex = c.ElementsBefore.Count
                Next
            Next

이 스레드의 일부 예제는 Z 이상으로 작동하지 않았습니다.

유효성을 검사할 때는 몇 가지 단위 테스트를 수행하여 열 인덱스가 올바르게 계산되었는지 확인하는 것이 좋습니다.

인덱스 카운트가 1부터 시작된다고 가정하면 다음은 유용한 참조가 될 수 있습니다.

Excel letter index calculation

언급URL : https://stackoverflow.com/questions/28875815/get-the-column-index-of-a-cell-in-excel-using-openxml-c-sharp

반응형