如何使用 C# 讀取文件中的表格

This article was translated from English: Does it need improvement?
Translated
View the article in English

讓我們來談談如何讀取文件中的表格。 使用純 Tesseract 從表格中提取資料可能具有挑戰性,因為文字通常位於單元格中,並且稀疏地分散在整個文件中。 但是,我們的庫配備了一個機器學習模型,該模型經過訓練和微調,可以準確地檢測和提取表格資料。

對於簡單的表格,您可以依賴直接的表格檢測;而對於更複雜的結構,我們獨特的ReadDocumentAdvanced方法可提供強大的結果,有效地解析表格並提供資料。

快速入門:一次呼叫提取複雜表格單元格

幾分鐘即可上手使用——本範例展示如何使用 ReadDocumentAdvanced 進行一次 IronOCR 調用,從複雜的文檔中獲取詳細的表格單元格資料。 它透過載入 PDF、應用進階表格檢測並直接返回儲存格資訊清單來展示易用性。

Nuget Icon立即開始使用 NuGet 建立 PDF 檔案:

  1. 使用 NuGet 套件管理器安裝 IronOCR

    PM > Install-Package IronOcr

  2. 複製並運行這段程式碼。

    var cells = new IronTesseract().ReadDocumentAdvanced(new OcrInput().LoadPdf("invoiceTable.pdf")).Tables.First().CellInfos;
  3. 部署到您的生產環境進行測試

    立即開始在您的專案中使用 IronOCR,免費試用!
    arrow pointer

以下步驟引導您開始使用 IronOCR 讀取表格:


簡單表格範例

ReadDataTables屬性設為 true 可啟用使用 Tesseract 進行表格偵測。 我創建了一個簡單的表格 PDF 來測試這個功能,你可以從這裡下載:' simple-table.pdf '。 可以使用此方法檢測沒有合併單元格的簡單表格。 對於更複雜的表格,請參考下面所述的方法。

:path=/static-assets/ocr/content-code-examples/how-to/read-table-in-document-with-tesseract.cs
using IronOcr;
using System;
using System.Data;

// Instantiate OCR engine
var ocr = new IronTesseract();

// Enable table detection
ocr.Configuration.ReadDataTables = true;

using var input = new OcrPdfInput("simple-table.pdf");
var result = ocr.Read(input);

// Retrieve the data
var table = result.Tables[0].DataTable;

// Print out the table data
foreach (DataRow row in table.Rows)
{
    foreach (var item in row.ItemArray)
    {
        Console.Write(item + "\t");
    }
    Console.WriteLine();
}
Imports Microsoft.VisualBasic
Imports IronOcr
Imports System
Imports System.Data

' Instantiate OCR engine
Private ocr = New IronTesseract()

' Enable table detection
ocr.Configuration.ReadDataTables = True

Dim input = New OcrPdfInput("simple-table.pdf")
Dim result = ocr.Read(input)

' Retrieve the data
Dim table = result.Tables(0).DataTable

' Print out the table data
For Each row As DataRow In table.Rows
	For Each item In row.ItemArray
		Console.Write(item & vbTab)
	Next item
	Console.WriteLine()
Next row
$vbLabelText   $csharpLabel

閱讀發票範例

在商業環境中,發票是比較常見的複雜表格之一。 發票本身就是複雜的表格,包含行和列資料。 使用 IronOCR,我們利用ReadDocumentAdvanced方法來完美地處理它們。 該過程包括掃描文件、識別表格結構和提取資料。 在這個範例中,我們將使用" invoiceTable.pdf "檔案來展示IronOCR如何從發票中檢索所有資訊。

ReadDocumentAdvanced方法需要將IronOcr.Extensions.AdvancedScan軟體包與基礎 IronOCR 軟體包一起安裝。

[{i:( 在 .NET Framework 上使用進階掃描功能需要專案在 x64 架構上運作。 進入專案配置,取消選取"首選 32 位元"選項即可實現此目的。 請參閱以下故障排除指南以了解更多資訊:". NET Framework 進階掃描"。 @@--括號關閉--@@

:path=/static-assets/ocr/content-code-examples/how-to/read-table-in-document-with-ml.cs
using IronOcr;
using System.Linq;

// Instantiate OCR engine
var ocr = new IronTesseract();

using var input = new OcrInput();
input.LoadPdf("invoiceTable.pdf");

// Perform OCR
var result = ocr.ReadDocumentAdvanced(input);

var cellList = result.Tables.First().CellInfos;
IRON VB CONVERTER ERROR developers@ironsoftware.com
$vbLabelText   $csharpLabel

此方法將文件中的文字資料分為兩類:一類有邊框,另一類沒有邊框。 對於有邊框的內容,圖書館會根據表格的結構進一步細分為小節。 結果如下圖所示。 值得注意的是,由於此方法側重於邊界內的信息,因此任何跨越多行的合併單元格都將被視為單一單元格。

結果

在文件中讀取表格

輔助類

在目前實作中,提取的單元格尚未正確組織。 但是,每個單元格都包含有價值的信息,例如 X 和 Y 座標、尺寸等等。 利用這些數據,我們可以建立一個用於各種用途的輔助類別。 以下是一些基本輔助方法:

using System;
using System.Collections.Generic;
using System.Linq;

// A helper class to process table data by sorting cells based on coordinates
public static class TableProcessor
{
    // Method to organize cells by their coordinates (Y top to bottom, X left to right)
    public static List<CellInfo> OrganizeCellsByCoordinates(List<CellInfo> cells)
    {
        // Sort cells by Y (top to bottom), then by X (left to right)
        var sortedCells = cells
            .OrderBy(cell => cell.CellRect.Y)
            .ThenBy(cell => cell.CellRect.X)
            .ToList();

        return sortedCells;
    }

    // Example method demonstrating how to process multiple tables
    public static void ProcessTables(Tables tables)
    {
        foreach (var table in tables)
        {
            var sortedCells = OrganizeCellsByCoordinates(table.CellInfos);

            Console.WriteLine("Organized Table Cells:");

            // Initialize previous Y coordinate
            int previousY = sortedCells.Any() ? sortedCells.First().CellRect.Y : 0;

            foreach (var cell in sortedCells)
            {
                // Print a new line if the Y-coordinate changes, indicating a new row
                if (Math.Abs(cell.CellRect.Y - previousY) > cell.CellRect.Height * 0.8)
                {
                    Console.WriteLine();  // Start a new row
                    previousY = cell.CellRect.Y;
                }

                // Print the cell text followed by a tab
                Console.Write($"{cell.CellText}\t");
            }

            Console.WriteLine("\n--- End of Table ---");  // End of a table
        }
    }

    // Method to extract a specific row by the given index
    public static List<CellInfo> ExtractRowByIndex(TableInfo table, int rowIndex)
    {
        if (table == null || table.CellInfos == null || !table.CellInfos.Any())
        {
            throw new ArgumentException("Table is empty or invalid.");
        }

        var sortedCells = OrganizeCellsByCoordinates(table.CellInfos);
        List<List<CellInfo>> rows = new List<List<CellInfo>>();

        // Group cells into rows based on Y coordinates
        int previousY = sortedCells.First().CellRect.Y;
        List<CellInfo> currentRow = new List<CellInfo>();

        foreach (var cell in sortedCells)
        {
            if (Math.Abs(cell.CellRect.Y - previousY) > cell.CellRect.Height * 0.8)
            {
                // Store the completed row and start a new one
                rows.Add(new List<CellInfo>(currentRow));
                currentRow.Clear();

                previousY = cell.CellRect.Y;
            }

            currentRow.Add(cell);
        }

        // Add the last row if it wasn't added yet
        if (currentRow.Any())
        {
            rows.Add(currentRow);
        }

        // Retrieve the specified row
        if (rowIndex < 0 || rowIndex >= rows.Count)
        {
            throw new IndexOutOfRangeException($"Row index {rowIndex} is out of range.");
        }

        return rows[rowIndex];
    }
}
using System;
using System.Collections.Generic;
using System.Linq;

// A helper class to process table data by sorting cells based on coordinates
public static class TableProcessor
{
    // Method to organize cells by their coordinates (Y top to bottom, X left to right)
    public static List<CellInfo> OrganizeCellsByCoordinates(List<CellInfo> cells)
    {
        // Sort cells by Y (top to bottom), then by X (left to right)
        var sortedCells = cells
            .OrderBy(cell => cell.CellRect.Y)
            .ThenBy(cell => cell.CellRect.X)
            .ToList();

        return sortedCells;
    }

    // Example method demonstrating how to process multiple tables
    public static void ProcessTables(Tables tables)
    {
        foreach (var table in tables)
        {
            var sortedCells = OrganizeCellsByCoordinates(table.CellInfos);

            Console.WriteLine("Organized Table Cells:");

            // Initialize previous Y coordinate
            int previousY = sortedCells.Any() ? sortedCells.First().CellRect.Y : 0;

            foreach (var cell in sortedCells)
            {
                // Print a new line if the Y-coordinate changes, indicating a new row
                if (Math.Abs(cell.CellRect.Y - previousY) > cell.CellRect.Height * 0.8)
                {
                    Console.WriteLine();  // Start a new row
                    previousY = cell.CellRect.Y;
                }

                // Print the cell text followed by a tab
                Console.Write($"{cell.CellText}\t");
            }

            Console.WriteLine("\n--- End of Table ---");  // End of a table
        }
    }

    // Method to extract a specific row by the given index
    public static List<CellInfo> ExtractRowByIndex(TableInfo table, int rowIndex)
    {
        if (table == null || table.CellInfos == null || !table.CellInfos.Any())
        {
            throw new ArgumentException("Table is empty or invalid.");
        }

        var sortedCells = OrganizeCellsByCoordinates(table.CellInfos);
        List<List<CellInfo>> rows = new List<List<CellInfo>>();

        // Group cells into rows based on Y coordinates
        int previousY = sortedCells.First().CellRect.Y;
        List<CellInfo> currentRow = new List<CellInfo>();

        foreach (var cell in sortedCells)
        {
            if (Math.Abs(cell.CellRect.Y - previousY) > cell.CellRect.Height * 0.8)
            {
                // Store the completed row and start a new one
                rows.Add(new List<CellInfo>(currentRow));
                currentRow.Clear();

                previousY = cell.CellRect.Y;
            }

            currentRow.Add(cell);
        }

        // Add the last row if it wasn't added yet
        if (currentRow.Any())
        {
            rows.Add(currentRow);
        }

        // Retrieve the specified row
        if (rowIndex < 0 || rowIndex >= rows.Count)
        {
            throw new IndexOutOfRangeException($"Row index {rowIndex} is out of range.");
        }

        return rows[rowIndex];
    }
}
Imports Microsoft.VisualBasic
Imports System
Imports System.Collections.Generic
Imports System.Linq

' A helper class to process table data by sorting cells based on coordinates
Public Module TableProcessor
	' Method to organize cells by their coordinates (Y top to bottom, X left to right)
	Public Function OrganizeCellsByCoordinates(ByVal cells As List(Of CellInfo)) As List(Of CellInfo)
		' Sort cells by Y (top to bottom), then by X (left to right)
		Dim sortedCells = cells.OrderBy(Function(cell) cell.CellRect.Y).ThenBy(Function(cell) cell.CellRect.X).ToList()

		Return sortedCells
	End Function

	' Example method demonstrating how to process multiple tables
	Public Sub ProcessTables(ByVal tables As Tables)
		For Each table In tables
			Dim sortedCells = OrganizeCellsByCoordinates(table.CellInfos)

			Console.WriteLine("Organized Table Cells:")

			' Initialize previous Y coordinate
			Dim previousY As Integer = If(sortedCells.Any(), sortedCells.First().CellRect.Y, 0)

			For Each cell In sortedCells
				' Print a new line if the Y-coordinate changes, indicating a new row
				If Math.Abs(cell.CellRect.Y - previousY) > cell.CellRect.Height * 0.8 Then
					Console.WriteLine() ' Start a new row
					previousY = cell.CellRect.Y
				End If

				' Print the cell text followed by a tab
				Console.Write($"{cell.CellText}" & vbTab)
			Next cell

			Console.WriteLine(vbLf & "--- End of Table ---") ' End of a table
		Next table
	End Sub

	' Method to extract a specific row by the given index
	Public Function ExtractRowByIndex(ByVal table As TableInfo, ByVal rowIndex As Integer) As List(Of CellInfo)
		If table Is Nothing OrElse table.CellInfos Is Nothing OrElse Not table.CellInfos.Any() Then
			Throw New ArgumentException("Table is empty or invalid.")
		End If

		Dim sortedCells = OrganizeCellsByCoordinates(table.CellInfos)
		Dim rows As New List(Of List(Of CellInfo))()

		' Group cells into rows based on Y coordinates
		Dim previousY As Integer = sortedCells.First().CellRect.Y
		Dim currentRow As New List(Of CellInfo)()

		For Each cell In sortedCells
			If Math.Abs(cell.CellRect.Y - previousY) > cell.CellRect.Height * 0.8 Then
				' Store the completed row and start a new one
				rows.Add(New List(Of CellInfo)(currentRow))
				currentRow.Clear()

				previousY = cell.CellRect.Y
			End If

			currentRow.Add(cell)
		Next cell

		' Add the last row if it wasn't added yet
		If currentRow.Any() Then
			rows.Add(currentRow)
		End If

		' Retrieve the specified row
		If rowIndex < 0 OrElse rowIndex >= rows.Count Then
			Throw New IndexOutOfRangeException($"Row index {rowIndex} is out of range.")
		End If

		Return rows(rowIndex)
	End Function
End Module
$vbLabelText   $csharpLabel

常見問題解答

如何使用 C# 改進文檔中的表格數據提取?

您可以通過使用 IronOCR 的機器學習模型來提高文檔中的表格數據提取,該模型經過專門訓練,可以準確檢測和提取複雜的表格數據。這種方法比使用標準 OCR 工具如 Tesseract 更有效。

IronOCR 中的 `ReadDocumentAdvanced` 方法的目的是什麼?

IronOCR 中的 `ReadDocumentAdvanced` 方法旨在通過有效的解析和數據提取來處理複雜表格,它在處理具有複雜結構的表格方面特別有用。

如何開始使用 IronOCR 的表格提取?

若要開始使用 IronOCR 提取表格,請下載 C# 庫,準備您的文檔,通過設置 ReadDataTables 屬性啟用表格檢測,並對複雜表格使用 ReadDocumentAdvanced 方法。

IronOCR 高級表格提取需要哪些額外的包?

IronOCR 高級表格提取需要特定於 Windows 的 `IronOcr.Extensions.AdvancedScan` 包,以有效管理複雜表格結構。

如何使用 IronOCR 組織提取的表格數據?

IronOCR提供幫助方法,通過座標組織提取的表格數據,讓你可以處理多個表格並按索引提取特定行,從而實現更好的數據管理。

使用 IronOCR 提取的表格單元格中包含哪些元數據?

使用 IronOCR 提取的表格單元格包括如 X 和 Y 坐標、單元格尺寸以及每個單元格內的文本內容等元數據,從而實現詳細的數據分析和組織。

使用 IronOCR 進行表格提取時,如何確保 .NET Framework 的兼容性?

為確保與 .NET Framework 的兼容性,請確保您的項目運行在 x64 架構上,並在項目配置中取消選中“優先使用 32 位”選項。

Curtis Chau
技術作家

Curtis Chau 擁有卡爾頓大學計算機科學學士學位,專注於前端開發,擅長於 Node.js、TypeScript、JavaScript 和 React。Curtis 熱衷於創建直觀且美觀的用戶界面,喜歡使用現代框架並打造結構良好、視覺吸引人的手冊。

除了開發之外,Curtis 對物聯網 (IoT) 有著濃厚的興趣,探索將硬體和軟體結合的創新方式。在閒暇時間,他喜愛遊戲並構建 Discord 機器人,結合科技與創意的樂趣。

審核人
Jeff Fritz
Jeffrey T. Fritz
首席程序经理 - .NET 社区团队
Jeff 也是 .NET 和 Visual Studio 团队的首席程序经理。他是 .NET Conf 虚拟会议系列的执行制作人,并主持“Fritz 和朋友”这一每周两次的开发者的直播节目,在节目上讨论技术并与观众一起编写代码。Jeff 撰写研讨会、主持演讲,并计划大型 Microsoft 开发者活动(包括 Microsoft Build、Microsoft Ignite、.NET Conf 和 Microsoft MVP Summit)的内容。
準備好開始了嗎?
Nuget 下載 5,167,857 | Version: 2025.11 剛發表