使用OpenXML C#在Excel中获取单元格的列索引

QV1*_*QV1 14 c# excel openxml

我一直在寻找一段时间,似乎无法找到如何做到这一点.我有一张excel表,我正在使用OpenXML阅读.现在正常情况是循环遍历行然后循环遍历单元格以获取值,这很好.但是随着值的增加,我需要单元格的位置,格式为(rowindex,ColumnIndex).我已经设法得到了rowIndex,但似乎无法弄清楚索引列.

我实际上认为这很容易,但显然它不是.

pet*_*ids 21

这比您想象的要复杂一些,因为模式允许省略空单元格.

为了获得该指数可以用Cellwihch有一个对象CellReference,让格式参考属性A1,B1等等.你可以使用该引用来提取列数.

正如你可能知道,在Excel中A = 1,B = 2等多达Z = 26此时细胞的前缀AAA = 27,AB = 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
Run Code Online (Sandbox Code Playgroud)

在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;
}
Run Code Online (Sandbox Code Playgroud)

请注意,CellReference保证是在XML或者(虽然我从来没有见过它不存在).在CellReference空的情况下,将单元放置在最左边的可用单元中.本RowIndex也没有在该规范的强制性,因此也能在这种情况下,细胞被置于可用的最高行中被省略.在这个问题中可以看到更多信息.将答案从@BCdotWEB是在情况下,正确的做法CellReferencenull.


小智 8

小是美丽的

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;
}
Run Code Online (Sandbox Code Playgroud)


Joe*_*Joe 7

    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);
            }
        }
    }
Run Code Online (Sandbox Code Playgroud)


Joh*_*son 5

    [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 );
Run Code Online (Sandbox Code Playgroud)