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

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

IronOCR使C#開發人員能夠使用先進的機器學習模型從PDF和圖像中的表格中提取資料,能夠通過ReadDocumentAdvanced方法處理基本單元格的簡單表格和具有合併單元格的複雜結構如發票。

使用普通Tesseract提取表格中的資料可能很具挑戰性,因為文字通常位於單元格中並且稀疏地分佈在整個文件中。 然而,我們的程式庫包含經過訓練和精調的機器學習模型,能夠準確地檢測和提取表格資料。 無論是處理財務報告、庫存清單還是發票資料,IronOCR都提供有效解析結構化資料所需的工具。

對於簡單的表格,依賴於使用標準OcrInput的直接表格檢測。 對於更複雜的結構,我們的專用方法ReadDocumentAdvanced提供了強健的結果,能夠有效解析表格並傳遞資料。 此高級方法利用機器學習來理解表格佈局、合併單元格和傳統OCR常常難以處理的複雜格式。

⟨AH2BG⟩快速開始:一次呼叫提取複雜的表格單元⟨AH2EG⟩

在幾分鐘內開始並運行—此範例顯示如何使用ReadDocumentAdvanced進行一次IronOCR呼叫,由此便可以從複雜的文件中獲得詳細的表格單元資料。
它通過載入PDF、應用高級表格檢測並直接返回單元資料列表,展示了使用的簡易性。

  1. 使用NuGet套件管理器安裝https://www.nuget.org/packages/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'。 使用此方法可以檢測沒有合併單元格的簡單表格。 對於更複雜的表格,請參閱下面描述的方法。

標準表格檢測方法特別適合於:

  • 試算表導出
  • 具備一致行/列結構的基本資料表
  • 含表格資料的報告
  • 簡單的庫存清單

如果一般情況下使用PDF OCR文字提取,此方法可以無縫整合到IronOCR更廣泛的文件處理功能中。

: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包。 此擴展提供專門針對複雜文件佈局設計的高級機器學習功能。

請注意
在.NET Framework上進行高級掃描需要項目在x64架構下執行。 導航到項目配置並取消勾選"偏好32位"選項以實現此目的。 在以下故障排除指南中了解更多資訊:"Advanced Scan on .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;
Imports IronOcr
Imports System.Linq

' Instantiate OCR engine
Dim ocr = New IronTesseract()

Using input As New OcrInput()
    input.LoadPdf("invoiceTable.pdf")

    ' Perform OCR
    Dim result = ocr.ReadDocumentAdvanced(input)

    Dim cellList = result.Tables.First().CellInfos
End Using
$vbLabelText   $csharpLabel

此方法將文件的文字資料分為兩類:一類有邊框包圍,另一類無邊框。 對於有邊框的內容,程式庫進一步根據表格的結構將其劃分為子部分。 該方法在處理以下方面非常有用:

  • 具有不同描述的發票項目行
  • 多列的價格細分
  • 收/發貨地址塊
  • 稅額和總計計算部分
  • 頁眉和頁腳資訊

結果如下面所示。 由於此方法專注於以邊框包圍的資訊,任何跨越多行的合併單元格將被視為單個單元格。

提取的資料長什麼樣?

Iron Software OCR從運送發票中提取表格資料到結構化階層格式

我如何組織和處理提取的表格單元?

在當前的實施中,提取的單元尚未正確組織。 然而,每個單元包含有價值的資訊,如X和Y座標、尺寸等。 使用這些資料,我們可以建立一個助手類來用於各種目的。 單元資訊包括:

  • 用於定位的精確X/Y座標
  • 寬度和高度尺寸
  • 文字內容
  • 置信分數
  • 單元關係

此詳細資訊使您能夠透過程式重建表格結構,並應用自定義邏輯以提取資料。 您還可以使用這些座標定義特定區域以在後續操作中進行針對性OCR處理。

以下是一些基本的助手方法:

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

表格提取的最佳做法

在IronOCR中進行表格提取時,請考慮以下最佳做法:

  1. 文件質量:較高解析度的文件產生更好的結果。 對於掃描文件,確保至少有300 DPI。

  2. 預處理:對於質量不佳或表格傾斜的文件,考慮在處理前使用IronOCR的圖像校正功能。

  3. 性能:對於包含多個表格的大型文件,考慮使用多執行緒和非同步支持以並行處理頁面。

  4. 輸出選項:在提取表格資料後,您可以以多種格式導出結果。 了解更多資料輸出選項以及如何從處理後的文件中建立可搜尋的PDFs

  5. 流處理:對於網頁應用或使用記憶體中文件的場景,考慮使用PDF流的OCR以避免文件系統操作。

總結

IronOCR透過基於標準Tesseract的檢測和高級機器學習方法提供強大的表格提取功能。 標準方法對於簡單表格效果極佳,而ReadDocumentAdvanced方法在如發票等複雜文件中表現出色。 藉助提供的助手方法,您可以組織和處理提取的資料以滿足您的特定需求。

探索更多IronOCR功能以增強您的文件處理工作流程並在您的.NET應用中充分發揮光學字元識別的潛力。

常見問題

如何在C#中從PDF和影像中擷取表格資料?

IronOCR使C#開發者能夠使用先進的機器學習模型從PDF和影像中擷取表格資料。對於簡單表格,使用OcrInput類並將ReadDataTables屬性設為true。對於具有合併單元格的複雜表格,使用ReadDocumentAdvanced方法以獲得更準確的結果。

簡單和複雜表格擷取有什麼區別?

IronOCR中的簡單表格擷取使用ReadDataTables屬性與Tesseract,適合具有清晰單元格邊界的基礎表格。複雜表格擷取需要使用ReadDocumentAdvanced方法,該方法使用機器學習處理合併單元格、發票和複雜格式。

如何快速擷取複雜表格中的資料?

使用IronOCR的ReadDocumentAdvanced方法以單次調用:var cells = new IronTesseract().ReadDocumentAdvanced(new OcrInput().LoadPdf('invoiceTable.pdf')).Tables.First().CellInfos;這利用機器學習來理解表格佈局和複雜格式。

什麼型別的文件最適合簡單表格檢測?

IronOCR的簡單表格檢測方法特別適合電子表格匯出、具有一致行/列結構的基礎資料表、帶有表格式資料的報告以及沒有合併單元格的簡單庫存清單。

如何為基礎表格啟用表格檢測?

在IronOCR中為基礎表格啟用表格檢測,將ReadDataTables屬性設為true。這使用Tesseract的表格檢測能力,適合具有清晰單元格邊界且沒有合併單元格的表格。

程式庫可以處理具有複雜佈局的發票和財務報告嗎?

可以,IronOCR的ReadDocumentAdvanced方法專為處理如發票和財務報告等複雜文件而設計。它使用經過訓練的機器學習模型來檢測和擷取具有合併單元格和複雜格式的表格資料。

IronOCR能整合到現有的應用程式中嗎?

IronOCR被設計成可以輕鬆地整合到現有應用程式中,使用C#允許開發人員以最小的努力為其軟體新增OCR功能。

使用IronOCR進行文件管理的好處是什麼?

使用IronOCR進行文件管理通過將掃描的文件轉換為可搜索和可編輯的文字來簡化工作流程,減少手動資料輸入的需求並提高文件的可存取性。

IronOCR如何提高資料精確性?

IronOCR通過其先進的識別算法和影像校正功能提高資料精確性,確保文字提取過程既可靠又精確。

IronOCR有免費試用版嗎?

有的,Iron Software提供IronOCR的免費試用版,允許使用者在做出購買決定前測試其功能和能力。

Curtis Chau
技術作家

Curtis Chau擁有Carleton大學的電腦科學學士學位,專精於前端開發,擁有Node.js、TypeScript、JavaScript和React的專業知識。Curtis熱衷於建立直觀且美觀的使用者介面,喜愛使用現代框架並建立結構良好、視覺吸引力的手冊。

除了開發,Curtis對物聯網(IoT)有濃厚的興趣,探索創新的方法來整合硬體和軟體。在空閒時間,他喜歡玩遊戲和建立Discord機器人,結合他對技術的熱愛與創造力。

由...審核
Jeff Fritz
Jeffrey T. Fritz
首席計劃經理 - .NET社區團隊
Jeff還是.NET和Visual Studio團隊的首席計劃經理。他是.NET Conf虛擬會議系列的執行製作人,並主持每週兩次的開發者直播節目'Fritz and Friends',在節目中討論技術並與觀眾一起撰寫程式碼。Jeff撰寫工作坊、演講和內容計劃,為微軟開發者的最大活動如Microsoft Build、Microsoft Ignite、.NET Conf和Microsoft MVP Summit提供內容支援。
準備開始了嗎?
Nuget 下載 6,136,090 | 版本: 2026.7 剛剛發布
Still Scrolling Icon

還在滾動?

想要快速證明? PM > Install-Package IronOcr
執行範例 觀看您的圖像轉變為可搜尋文字。