簡體   English   中英

使用 OpenXML C# 獲取 Excel 中單元格的列索引

[英]Get the Column Index of a Cell in Excel using OpenXML C#

我一直在環顧四周,似乎無法找到如何做到這一點。 我有一張 excel 表,我正在使用 OpenXML 閱讀它。 現在正常的做法是遍歷行,然后遍歷單元格以獲取值,這很好。 但是除了值之外,我還需要單元格的位置,格式為(rowindex,ColumnIndex)。 我設法獲得了rowIndex,但似乎無法弄清楚獲得列索引。

我實際上認為這很容易,但顯然不是。

這比您想象的要復雜一些,因為架構允許省略空單元格。

要獲取索引,您可以使用具有CellReference屬性的Cell對象,該屬性以A1B1等格式提供引用。您可以使用該引用來提取列號。

您可能知道,在 Excel A = 1B = 2等直到Z = 26時,單元格以A為前綴以給出AA = 27AB = 28等。請注意,在AA的情況下,第A值為秒的 26 倍; 即它“價值”26,而第二個A “價值”1,總共27。

要計算列索引,您可以反轉字母,然后取第一個字母的值並將其添加到運行總數中。 然后將第二個字母的值乘以 26,將總數與第一個數字相加。 對於第三個,您將其乘以 26 兩次並相加,對於第四個,將其乘以 26 3 次,依此類推。

因此,對於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;
}

請注意, CellReference不能保證在 XML 中(盡管我從未見過它不在那里)。 CellReference為空的情況下,單元格被放置在最左邊的可用單元格中。 RowIndex在規范中也不是強制性的,因此它也可以省略,在這種情況下,單元格放置在可用的最高行中。 更多信息可以在這個問題中看到。 CellReferencenull情況下, CellReference答案是正確的方法。

小就是美

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;
}
    [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 ,該單元格的形式為A1B2 ,實際上是COLUMN_ROW格式。

您可以做的是從CellReference提取 Row 和 Column 。 是的,這需要你來實現,你需要檢查的方法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]);
                        }
        }

這是為了找到存在/使用的列總數在此處輸入圖片說明

在我的場景中,我只需要處理列名(沒有單元格編號),並使用了 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函數。 結果將是從零開始的索引。 如果需要為基於 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;
}
    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);
            }
        }
    }
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;
    }

只是為了為這個老問題添加一種新方法,我使用它作為一種快速方法來獲取一行中單元格的列索引(假設您正在循環通過 SheetData 中的一行中的單元格,因為 OP 表明它們是)。

您可以使用 ElementsBefore 枚舉來計算您當前循環的單元格之前的單元格,並且由於該 Count 是從一開始的,而 Element IEnumerables 是從零開始的,因此使用 Count 將為您提供單元格的列索引。當前重新打開(本質上,ElementsBefore + 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字母索引計算

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM