2015-03-05 12 views
9

Od pewnego czasu rozglądam się i nie mogę się dowiedzieć, jak to zrobić. Mam arkusz excel, który czytam przy użyciu OpenXML. Teraz normalną rzeczą byłoby przechodzenie przez rzędy, a następnie przechodzenie przez komórki, aby uzyskać wartości, co jest w porządku. Ale wraz z wartościami potrzebuję lokalizacji komórki, która byłaby w formacie (rowindex, ColumnIndex). Udało mi się zdobyć rowIndex, ale nie mogę się domyślić, jak uzyskać indeks kolumny.Uzyskaj indeks kolumny komórki w programie Excel przy użyciu OpenXML C#

Myślałem, że to będzie łatwe, ale najwyraźniej tak nie jest.

+2

Dla przyszłych czytelników, polecam [widząc tę ​​odpowiedź] (http://stackoverflow.com/a/667902/906773). –

Odpowiedz

-7

Ponieważ można przechodzić przez komórki wiersza za pomocą Worksheet.Descendants<Cell>(), można po prostu użyć for-loop do określenia indeksu komórki.

+0

Idealny. Potrzebowałem tylko licznika. Głupi ja !! – QV1

+12

To nie zadziała, jeśli masz puste kolumny, ponieważ nie są one gwarantowane w XML. Jak mówi @KcDoD, będziesz musiał użyć 'CellReference'. Np. Jeśli "A1" i "C1" zawierają w sobie dane, ale "B1" nie może skończyć się myślą, że "C1" jest drugą kolumną, a nie trzecią. – petelids

+0

@petelids masz rację. Jeśli znajdziesz rozwiązanie, podaj je również. wielkie dzięki –

2

Aby rozpocząć odpowiedź, zapraszam najpierw do obejrzenia this.

Jak już wyjaśniłem, jest łatwy sposób na wyodrębnienie wiersza i kolumny z zakresu NO. Najbliższy jest ekstrakcja komórki CellReference, która miałaby postać A1, B2, która jest w rzeczywistości formatem COLUMN_ROW.

Co można zrobić, to wyodrębnić wiersz i kolumnę z CellReference. Tak, to wymagałoby zastosowania metody, w której należy sprawdzić char przez char, aby zweryfikować liczby i łańcuchy.

Powiedzmy, że masz A11, wtedy gdy potrzebujesz indeksować kolumnę, musisz wyodrębnić A, która dałaby jako column 1. Tak, to nie jest takie łatwe, ale jest to jedyny sposób, chyba że po prostu zdecydujesz się policzyć kolumny podczas skanowania/iteracji przez komórki.

Ponownie spójrz na this pytań odpowiedzi, która robi to samo.

+0

Hmm .. OK, ale potrzebuję tej kolumny Index.So, co teraz myślę, to znaleźć sposób na zastąpienie litery z odwołania do komórki, aby uzyskać indeks kolumny. – QV1

+0

Jak wyjaśniono w odpowiedzi, żadna ŁATWA droga :) po prostu nie liczy się tak, jak wskazałem w połączonym pytaniu :) –

+0

@ QV1 Czy dostałeś odpowiedź na pytanie? Lub potrzebujesz więcej wyjaśnień :) –

15

Trochę się spóźniłem, aby odpowiedzieć na to pytanie, ale zaakceptowana odpowiedź nie zadziała, jeśli w wierszu, w którym jesteś zainteresowany, są puste komórki, ponieważ nie gwarantują, że są w XML, schemat pozwala na pominięcie pustych komórek.

Aby uzyskać indeks można użyć obiektu Cell wihch ma właściwość CellReference który daje odniesienie w formacie A1, B1 itd. Można użyć tego odniesienia, aby wyodrębnić numer kolumny.

Jak zapewne wiecie, w programie Excel A = 1, B = 2 etc do Z = 26 w którym momencie komórki są poprzedzone A dać AA = 27, AB = 28 itd. Należy pamiętać, że w przypadku AA pierwszy A ma wartość 26 razy drugi; tzn. jest "warty" 26, podczas gdy drugi A jest "warty" 1, dając łącznie 27.

Aby obliczyć indeks kolumny, możesz odwrócić litery, a następnie przyjąć wartość pierwszej litery i dodać ją do suma całkowita. Następnie weź wartość drugiej litery i pomnóż ją przez 26, dodając sumę do pierwszej liczby. Za trzecią liczbę pomnożyć przez 26 dwukrotnie i dodać, czwarty pomnożyć przez 26 3 razy i tak dalej.

Tak na kolumnie ABC byś zrobił:

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

W języku C# dodaje zadziała:

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

Zauważ, że CellReference jest nie gwarancją w XML albo (chociaż Nigdy tego nie widziałem). W przypadku, gdy CellReference ma wartość null, komórka jest umieszczana w najbardziej dostępnej z lewej komórki. Model RowIndex nie jest również wymagany w specyfikacji, więc można go pominąć, w którym to przypadku komórka jest umieszczona w najwyższym dostępnym rzędzie. Więcej informacji można znaleźć w this question. Numer answer z @BCdotWEB to prawidłowe podejście w przypadkach, gdy CellReference jest null.

+0

Można zacząć od columnNumber = 0 i nie dodawać po powrocie. –

+0

Co by się stało z literą Z w drugiej literze? Czy nie byłby taki sam jak A na trzecim? Więc 'Z = 26 * 26' i' A = 1 * 26 * 26'. Pytam, ponieważ próbuję zrobić odwrotność, która idzie od indeksu komórki do nazwy komórki. – bostero2

+0

Litera "Z" na drugiej literze jest "warta" 26. Zostałaby dodana do 26 razy wartości pierwszej litery. Na przykład. 'ZZ' będzie' (26 * 26) + 26 = 702'. "A" w trzeciej kolumnie jest "warte" '1'. Zostałoby to dodane do 26 razy wartości drugiej litery i 26 * 26 razy wartości pierwszej. Np. "AAA" to '(26 * 26 * 1) + (26 * 1) + 1 = 703'. – petelids

6

Małe jest piękne

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

Chcesz wyjaśnić 64? – Yaron

+0

@ Yaron: 64 to ("A" - 1) – Captain

+0

@Captain thanks! – Yaron

2
[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); 
Powiązane problemy