c #: Есть ли способ получить адрес ячейки в Excel с того места, где начинаются данные?

#c# #winforms #excel-interop

#c# #winforms #excel-взаимодействие

Вопрос:

Я пытаюсь скопировать данные Excel с одного листа на другой. Работает нормально, но проблема в том, что в исходном файле, если данные не начинаются с ячейки A1 (рассмотрите изображение ниже), в этом случае я хочу скопировать данные из ячейки B5. Здесь Some header это не обязательно. Фактические данные начинаются с Emp ID ячейки.

Пример Excel

Что я пробовал, так это то, что я могу предоставить textbox для ввода в него адреса ячейки, а затем начать копирование данных с предоставленного адреса ячейки. Но это приводит к ручному вмешательству. Я хочу, чтобы это было автоматизировано. Любая помощь по этому вопросу приветствуется. Спасибо за помощь.

Комментарии:

1. Дайте нам четкое описание того, какие правила существуют для определения того, где начинаются данные . Они нам нужны, и наверняка они понадобятся компьютерной программе. Т.е. по каким критериям содержимое правила 3 не считается данными? Мы не можем просто использовать правило «я узнаю это, когда вижу».

2. @Damien_The_Unbeliever: Данные могут начинаться с любого места на листе. Правилом 3 может быть просто заголовок, подобный названию компании или аналитика, или что-то подобное Result set , который фактически не связан при объединении или извлечении данных.

3. Да, но если вы не можете придумать какие-то правила, которые мы можем применить, которые говорят, что является данными, а что не является данными, как вы можете ожидать, что компьютерная программа определит это? Как я уже сказал, мы не можем реализовать «я узнаю это, когда я это вижу». Например. это первая ячейка, которая также содержит непустые ячейки непосредственно под и справа от нее? Это правило, которое мы могли бы реализовать. Но мы не знаем, соответствует ли это вашим определениям.

4. Да, я понял вашу точку зрения. Вы правы, это первая ячейка, которая также содержит непустые ячейки непосредственно под ней и справа от нее. Но опять же, это может быть в одном конкретном файле, но не в другом. В другом файле, Emp ID может начинаться с ячейки A1 или может быть, Some header может вообще отсутствовать (первые несколько записей просто пустые). Так что в этом случае мое правило не будет иметь никакого эффекта. Я надеюсь, вы поняли мое мнение …?

5. @Damien_The_Unbeliever Я думаю, op не хочет иметь никаких строгих правил для операции копирования! Поскольку он указал, что может предоставить textbox для этого (но не хочет ручного вмешательства), он ожидает чего-то вроде автоматической выборки ячейки, где есть EmpID. Так ли это?

Ответ №1:

Предполагая некоторые базовые критерии, следующий код должен это сделать. Я предполагаю, что критериями являются: 1) если строка содержит какие-либо объединенные ячейки (например, ваш «Некоторый заголовок»), то это не начальная строка. 2) начальная ячейка будет содержать текст в ячейке справа и в ячейке под ней.

 private static bool RowIsEmpty(Range range)
{
  foreach (object obj in (object[,])range.Value2)
  {
    if (obj != null amp;amp; obj.ToString() != "")
    {
      return false;
    }
  }

  return true;
}

private static bool CellIsEmpty(Range cell)
{
  if (cell.Value2 != null amp;amp; cell.Value2.ToString() != "")
  {
    return false;
  }

  return true;
}

private Tuple<int, int> ExcelFindStartCell()
{
  var excelApp = new Microsoft.Office.Interop.Excel.Application();
  excelApp.Visible = true;

  Workbook workbook = excelApp.Workbooks.Open("test.xlsx");
  Worksheet worksheet = excelApp.ActiveSheet;

  // Go through each row.
  for (int row = 1; row < worksheet.Rows.Count; row  )
  {
    Range range = worksheet.Rows[row];

    // Check if the row is empty.
    if (RowIsEmpty(range))
    {
      continue;
    }

    // Check if the row contains any merged cells, if so we'll assume it's
    // some kind of header and move on.
    object mergedCells = range.MergeCells;
    if (mergedCells == DBNull.Value || (bool)mergedCells)
    {
      continue;
    }

    // Find the first column that contains text in this row.
    for (int col = 1; col < range.Columns.Count; col  )
    {
      Range cell = range.Cells[1, col];

      if (CellIsEmpty(cell))
      {
        continue;
      }

      // Now check if the cell to the right also contains text.
      Range rightCell = worksheet.Cells[row, col   1];

      if (CellIsEmpty(rightCell))
      {
        // No text in right cell, try the next row.
        break;
      }

      // Now check if cell below also contains text.
      Range bottomCell = worksheet.Cells[row   1, col];

      if (CellIsEmpty(bottomCell))
      {
        // No text in bottom cell, try the next row.
        break;
      }

      // Success!
      workbook.Close();
      excelApp.Quit();
      return new Tuple<int, int>(row, col);
    }
  }

  // Didn't find anything that matched the criteria.
  workbook.Close();
  excelApp.Quit();
  return null;
}
  

Комментарии:

1. Да, это работает, но я немного изменил решение. Я обновил ответ. Большое вам спасибо gunnerone 🙂