【问题标题】:Read specific value based on label name from PDF in C#在 C# 中根据 PDF 中的标签名称读取特定值
【发布时间】:2019-10-03 09:15:37
【问题描述】:

我有一个asp.net Core 2.0 C# 应用程序,它读取/解析 PDF 文件并获取文本。在此我想读取具有特定标签名称的特定值。您可以看到下图 我想获取值171857,即Invoice 数字并将其存储在数据库中。

我已尝试使用以下代码使用iTextSharp 阅读 pdf。

using (PdfReader reader = new PdfReader(fileName))
        {
            StringBuilder sb = new StringBuilder();

            ITextExtractionStrategy strategy = new SimpleTextExtractionStrategy();
            for (int page = 0; page < reader.NumberOfPages; page++)
            {
                string text = PdfTextExtractor.GetTextFromPage(reader, page + 1, strategy);
                if (!string.IsNullOrWhiteSpace(text))
                {
                    sb.Append(Encoding.UTF8.GetString(ASCIIEncoding.Convert(Encoding.Default, Encoding.UTF8, Encoding.Default.GetBytes(text))));
                }
            }

            var pdfText = sb.ToString();
        }

pdfText 变量中,我将从 pdf 中获取所有文本内容,但似乎这不是获取发票编号的正确方法。有没有其他方法可以通过标签名称从 pdf 中读取特定内容,例如我们将提供标签名称 Invoice 并返回值 171857 作为其他 3rd 方 pdf 阅读器库的示例?

任何帮助或建议将不胜感激。

谢谢

【问题讨论】:

  • 首先“有没有其他方法可以...与其他 3rd 方 pdf 阅读器库一起使用?”显然是对图书馆推荐的请求,这(同时)在堆栈溢出时是题外话(有一个软件推荐堆栈交换站点)。但即使忽略你在itextpdfsharp 都标记了你的问题的那部分;基本上你应该决定你想使用哪个库,自己认真尝试这样做,如果它不起作用,问一个特定于你选择的库的问题
  • 话虽如此,很可能您在 PDF 中的“标签”及其“值”只是碰巧彼此非常接近的文本。要么是表单字段值,要么是任意注释,要么是页面内容的一部分(直接或间接);此外,任何一个都可以绘制为位图图像或矢量图像,或者使用文本绘制指令,无论是否具有足够的文本提取信息。因此,请澄清它们的性质,因为提取方法取决于此。
  • @Ranadheer 正如上面 cmets 中所解释的,这个问题有些不清楚,需要进行一些澄清。 OP未能澄清,但可能你是赏金开启者。特别是解释标签和值的性质或在此处提供示例 PDF 代表。
  • 在我的工作中,我们使用了 Google Cloud Vision API 的 OCR。 PDF 被转换为字符串。他们我们找到了模式。在你的情况下,我会在关键词“Invoce”和“Date”之间寻找一个数字。您可以分析您的真实文本并找到更好的模式。

标签: c# pdf itext pdfparser


【解决方案1】:

假设发票标签和发票编号嵌入为 PDF 中的文本而不是位图。

我能想到的一种方法是使用Spire.PDF 并提取标签的位置,然后找到写在该位置正下方的数字。如果您拥有所有要处理的 PDF 的相同模板,这将相对简单。

【讨论】:

    【解决方案2】:

    从答案中无法立即明确pdfText 是否将包含发票编号以及文本的其余部分,但我会假设它会包含。如果没有,那么您将需要 OCR,这是完全不同的野兽。

    在这种情况下,我的第一反应是构建一个正则表达式 (^\d{6}$) 并尝试将其应用于页面上的所有文本。如果只有一个匹配项(发票编号),那就太好了!否则,如果它匹配更多的东西,你可以找到所有的出现并寻找一个模式。例如,如果客户的 ID 也与该正则表达式匹配,您可以提取所有包含匹配数字的行,并丢弃所有包含其他信息的行(可能所有带有客户 # 的行也有特定日期例如格式)。基本上找到所有正则表达式可以匹配的出现,并尝试找到规则来排除所有你不关心的出现。

    【讨论】:

      【解决方案3】:

      我帮助一位朋友从 Excel arc 生成的 pdf 发票中提取了类似的值。我已为此答案创建了 Excel 发票并将其打印为 PDF 文件和zipped 以供下载以进行测试。

      接下来我将使用一个名为PDFClown 的开源免费库。这是它的nuget 包。

      到目前为止一切顺利,我所做的是扫描所有 pdf 文档(例如发票可以是一页或多页),将每个内容添加到字符串列表中。

      下一步我找到索引(发票编号索引可以在列表中的第 10 个元素中,在我们的例子中是索引 1)引用发票价值,我将其称为标签或标签。

      因此我没有您的 pdf 文件,因此我即兴创作并添加了一个名为(或任何其他名称)“INVOICE”的独特标签。在这种情况下,发票编号位于发票标签之后。所以我找到“INVOICE”标签的索引并将索引加1这是因为发票编号跟随发票标签。这样,在这种情况下,我将选择发票文本 0005 并将其作为值 5 返回。这样,您可以获取每个文本/值后跟我们列表中扫描的任何标签的内容,并以您需要的方式返回。

      因此,您需要稍微调整一下以使其 100% 适合您的 pdf 文件。

      这是我的测试文件 Excel 和 Pdf zipped 下来。下载它进行测试。

      代码如下:

      public class InvoiceTextExtraction
      {
          private List<string> _contentList;
      
          public void GetValueFromPdf()
          {
              _contentList = new List<string>();
              CreatePdfContent(@"C:\temp\Invoice1.pdf");
      
              var index = _contentList.FindIndex(e => e == "INVOICE") + 1;
              int.TryParse(_contentList[index], out var value);
              Console.WriteLine(value);
          }
      
      
          public void CreatePdfContent(string filePath)
          {
              using (var file = new File(filePath))
              {
                  var document = file.Document;
      
                  foreach (var page in document.Pages)
                  {
                      Extract(new ContentScanner(page));
                  }
              }
          }
      
          private void Extract(ContentScanner level)
          {
              if (level == null)
                  return;
      
              while (level.MoveNext())
              {
                  var content = level.Current;
                  switch (content)
                  {
                      case ShowText text:
                      {
                          var font = level.State.Font;
                          _contentList.Add(font.Decode(text.Text));
                          break;
                      }
                      case Text _:
                      case ContainerObject _:
                          Extract(level.ChildLevel);
                          break;
                  }
              }
          }
      }
      

      从 pdf 文件中提取的输入。代码扫描返回以下元素:

      INVOICE
      0005
      
      PAYMENT DUE BY:
      4/19/2019
      .etc
      .
      .
      .
      Tax
      USD TOTAL
      171857
      18 september 2019
      

      这是结果

      5
      

      代码的灵感来自link

      【讨论】:

      猜你喜欢
      • 2012-12-04
      • 1970-01-01
      • 2019-08-10
      • 1970-01-01
      • 2015-07-17
      • 2022-12-07
      • 2019-07-09
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多