.NETとC#でPDFのテーブルをテキスト、CSV、Excelファイルに抽出

PDF文書は、プラットフォームを問わず安定した表示とフォーマットの保持が可能なため、構造化データの保存に広く利用されています。しかし、表データの編集が困難であるため、手作業による転記は非効率であり、エラーが発生しやすいという課題があります。C#を使用することで、PDFの表データを自動的に抽出し、手入力によるミスを回避できるだけでなく、CSVやExcelなどデータ分析に適した形式に変換できます。これにより、データの直接分析やデータベースへのインポートが容易になります。本記事では、**C#を使用して.NET環境でPDFの表を抽出し、テキスト、CSV、Excelファイルに保存する方法**を紹介します。

- **[C#でPDFの表データを抽出](#cでpdfの表データを抽出)**
- **[C#でPDFの表をCSVに変換](#cでpdfの表をcsvに変換)**
- **[C#でPDFの表をExcelファイルに出力](#cでpdfの表をexcelファイルに出力)**

本記事で紹介する方法では、無料で利用できる[Free Spire.PDF for .NET](https://jp.e-iceblue.com/introduce/free-spire-pdf-for-net.html)を使用します。NuGetからインストールできます：

`PM> Install-Package FreeSpire.PDF`

## C#でPDFの表データを抽出

`PdfTableExtractor`クラスを使用すると、PDF文書から表を抽出できます。その中の`PdfTableExtractor.ExtractTable()`メソッドを利用すると、指定したページの表を取得し、リストとして返すことができます。このリストを順に処理し、`PdfTable.GetText()`メソッドを使用して行や列のデータを取得できます。以下の手順で実装します。

1. 必要なモジュールをインポート。
2. `PdfDocument`オブジェクトを作成し、`PdfDocument.LoadFromFile()`メソッドでPDF文書を読み込む。
3. `PdfDocument`オブジェクトを使用して`PdfTableExtractor`インスタンスを作成。
4. 文書内の各ページを走査し、`PdfTableExtractor.ExtractTable()`メソッドで表を抽出。
5. 抽出された表リストが空でない場合、各表を走査し、`PdfTable.GetText()`メソッドでセルのテキストを取得。
6. 取得したデータをテキストファイルに書き込む。
7. リソースを解放。

**コード例**
```csharp
using Spire.Pdf;
using Spire.Pdf.Utilities;
using System.Text;

namespace ExtractPDFTableToText
{
    class Program
    {
        static void Main(string[] args)
        {
            // PdfDocumentクラスのインスタンスを作成
            PdfDocument pdf = new PdfDocument();

            // PDFドキュメントを読み込む
            pdf.LoadFromFile("Sample.pdf");

            // PdfTableExtractorクラスのインスタンスを作成
            PdfTableExtractor tableExtractor = new PdfTableExtractor(pdf);

            // PDFドキュメント内のページをループしてテーブルを抽出
            for (int i = 0; i < pdf.Pages.Count; i++)
            {
                // 現在のページからテーブルを抽出
                PdfTable[] tables = tableExtractor.ExtractTable(i);

                // テーブルリストがnullでない場合、テーブルをループ処理
                if (tables != null)
                {
                    for (int j = 0; j < tables.Length; j++)
                    {
                        // 現在のテーブルを取得
                        PdfTable table = tables[j];
                        string tableData = "";

                        // テーブル内の行と列をループ処理
                        for (int k = 0; k < table.GetRowCount(); k++)
                        {
                            for (int l = 0; l < table.GetColumnCount(); l++)
                            {
                                // 現在のセルからテキストを取得
                                String cellText = table.GetText(k, l);
                                String cleanText = cellText.Replace("\r\n", "").Replace("\n", "");

                                if (l < table.GetColumnCount() - 1)
                                {
                                    tableData += cleanText + "\t";
                                }
                                else
                                {
                                    tableData += cleanText;
                                }
                            }
                            tableData += "\r\n";
                        }

                        // テーブルデータをテキストファイルに書き込む
                        File.WriteAllText($"output/Page-{i + 1}-Table-{j + 1}.txt", tableData, Encoding.UTF8);
                    }
                }
            }

            // リソースを解放
            pdf.Close();
        }
    }
}
```

**抽出結果**

![C#でPDFの表データを抽出](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/278784/89c5f867-8e18-41aa-bc31-34120838b114.png)

## C#でPDFの表をCSVに変換

抽出した表データをCSV形式に適合するように処理し、CSVファイルとして出力できます。

**コード例**
```csharp
using Spire.Pdf;
using Spire.Pdf.Utilities;
using System.Text;

namespace ExtractPDFTableToText
{
    class Program
    {
        static void Main(string[] args)
        {
            // PdfDocumentクラスのインスタンスを作成
            PdfDocument pdf = new PdfDocument();

            // PDFドキュメントを読み込む
            pdf.LoadFromFile("Sample.pdf");

            // PdfTableExtractorクラスのインスタンスを作成
            PdfTableExtractor tableExtractor = new PdfTableExtractor(pdf);

            // PDFドキュメント内のページをループしてテーブルを抽出
            for (int i = 0; i < pdf.Pages.Count; i++)
            {
                // 現在のページからテーブルを抽出
                PdfTable[] tables = tableExtractor.ExtractTable(i);

                // テーブルリストがnullでない場合、テーブルをループ処理
                if (tables != null)
                {
                    for (int j = 0; j < tables.Length; j++)
                    {
                        // 現在のテーブルを取得
                        PdfTable table = tables[j];
                        string tableData = "";

                        // テーブル内の行と列をループ処理
                        for (int k = 0; k < table.GetRowCount(); k++)
                        {
                            for (int l = 0; l < table.GetColumnCount(); l++)
                            {
                                // 現在のセルのテキストを取得
                                String cellText = table.GetText(k, l);
                                // テキストを処理してCSV構造を壊さないようにする
                                String cleanText = CleanCsvField(cellText);

                                if (l < table.GetColumnCount() - 1)
                                {
                                    tableData += cleanText + ", ";
                                }
                                else
                                {
                                    tableData += cleanText;
                                }
                            }
                            tableData += "\r\n";
                        }

                        // テーブルデータをCSVファイルに書き込む
                        File.WriteAllText($"output/Page-{i + 1}-Table-{j + 1}.csv", tableData, Encoding.UTF8);
                    }
                }
            }

            // リソースを解放
            pdf.Close();
        }

        // CSV構造を壊す可能性のある文字を取り除く関数
        private static string CleanCsvField(string field)
        {
            // すべての改行を削除し、スペースをトリムする
            field = field.Replace("\r\n", "").Replace("\n", "").Replace("\r", "").Trim();

            bool mustQuote = field.Contains(",") || field.Contains("\"");
            if (mustQuote)
            {
                // 各ダブルクォートを2つのダブルクォートに置き換え、フィールド全体をダブルクォートで囲む
                return "\"" + field.Replace("\"", "\"\"") + "\"";
            }
            return field;
        }
    }
}
```

**抽出結果**

![C#でPDFの表をCSVに変換](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/278784/dc9dd553-0ffd-4238-9403-e892b36e3ace.png)

## C#でPDFの表をExcelファイルに出力

[Free Spire.XLS for .NET](https://jp.e-iceblue.com/introduce/free-spire-xls-for-net.html)（NuGet：`PM> Install-Package FreeSpire.XLS`）を併用すると、抽出した表データをExcelファイルとして保存できます。以下の手順で実装します。

1. 必要なモジュールをインポート。
2. `PdfDocument`オブジェクトを作成し、`PdfDocument.LoadFromFile()`メソッドでPDF文書を読み込む。
3. `Workbook`オブジェクトを作成し、新しいExcelワークブックを作成後、`Workbook.Worksheets.Clear()`メソッドでデフォルトのワークシートを削除。
4. `PdfDocument`オブジェクトを使用して`PdfTableExtractor`インスタンスを作成。
5. 文書内の各ページを走査し、`PdfTableExtractor.ExtractTable()`メソッドで表を抽出。
6. 抽出された表リストが空でない場合、`Workbook.Worksheets.Add()`メソッドで各表に対するワークシートを作成。
7. 各表の行と列を走査し、`PdfTable.GetText()`メソッドでセルのテキストを取得後、`Worksheet.Range[].Text`プロパティを使用してExcelのセルに書き込む。
8. `Workbook.SaveToFile()`メソッドを使用してExcelファイルを保存。
9. リソースを解放。

**コード例**
```csharp
using Spire.Pdf;
using Spire.Pdf.Utilities;
using Spire.Xls;

namespace ExtractPDFTableToText
{
    class Program
    {
        static void Main(string[] args)
        {
            // PdfDocumentクラスのインスタンスを作成
            PdfDocument pdf = new PdfDocument();

            // PDFドキュメントを読み込む
            pdf.LoadFromFile("Sample.pdf");

            // Workbookクラスのインスタンスを作成
            Workbook workbook = new Workbook();
            // デフォルトのワークシートを削除
            workbook.Worksheets.Clear();

            // PdfTableExtractorクラスのインスタンスを作成
            PdfTableExtractor tableExtractor = new PdfTableExtractor(pdf);

            // PDFドキュメント内のページをループしてテーブルを抽出
            for (int i = 0; i < pdf.Pages.Count; i++)
            {
                // 現在のページからテーブルを抽出
                PdfTable[] tables = tableExtractor.ExtractTable(i);

                // テーブルリストがnullでない場合、テーブルをループ処理
                if (tables != null)
                {
                    for (int j = 0; j < tables.Length; j++)
                    {
                        // 現在のテーブルを取得
                        PdfTable table = tables[j];
                        // ワークブック内にワークシートを作成
                        Worksheet sheet = workbook.Worksheets.Add($"Page-{i + 1}-Table-{j + 1}");

                        // テーブル内の行と列をループ処理
                        for (int k = 0; k < table.GetRowCount(); k++)
                        {
                            for (int l = 0; l < table.GetColumnCount(); l++)
                            {
                                // 現在のセルのテキストを取得
                                String cellText = table.GetText(k, l);
                                // 改行を削除
                                String cleanText = cellText.Replace("\r\n", "").Replace("\n", "");
                                // セルのテキストをワークシートの対応するセルに書き込む
                                sheet.Range[k + 1, l + 1].Text = cleanText;
                            }
                        }

                        // 列の幅を自動調整
                        for (int m = 0; m < sheet.AllocatedRange.ColumnCount; m++)
                        {
                            sheet.AutoFitColumn(m + 1);
                        }
                    }
                }
            }

            // ワークブックを保存
            workbook.SaveToFile("output/PDFTables.xlsx", ExcelVersion.Version2016);

            // リソースを解放
            pdf.Close();
            workbook.Dispose();
        }
    }
}
```

**抽出結果**

![C#でPDFの表をExcelファイルに出力](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/278784/f3bcd46f-ad63-4adb-ad18-396a07a03815.png)

本記事では、C#を使用して.NET環境でPDF文書の表データを抽出し、テキスト、CSV、およびExcelファイルに保存する方法を紹介しました。