使用 iText 从 pdf 文件中提取文本列

问题描述 投票:0回答:6
我需要使用 iText 从 pdf 文件中提取文本。

问题是:一些 pdf 文件包含 2 列,当我提取文本时,我得到一个文本文件,其中各列被合并为结果(即同一行中两列的文本)

这是代码:

public class pdf { private static String INPUTFILE = "http://www.revuemedecinetropicale.com/TAP_519-522_-_AO_07151GT_Rasoamananjara__ao.pdf" ; private static String OUTPUTFILE = "c:/new3.pdf"; public static void main(String[] args) throws DocumentException, IOException { Document document = new Document(); PdfWriter writer = PdfWriter.getInstance(document, new FileOutputStream(OUTPUTFILE)); document.open(); PdfReader reader = new PdfReader(INPUTFILE); int n = reader.getNumberOfPages(); PdfImportedPage page; // Go through all pages for (int i = 1; i <= n; i++) { page = writer.getImportedPage(reader, i); Image instance = Image.getInstance(page); document.add(instance); } document.close(); PdfReader readerN = new PdfReader(OUTPUTFILE); for (int i = 1; i <= n; i++) { String myLine = PdfTextExtractor.getTextFromPage(readerN,i); System.out.println(myLine); try { FileWriter fw = new FileWriter("c:/yo.txt",true); fw.write(myLine); fw.close(); }catch (IOException ioe) {ioe.printStackTrace(); } } }

你能帮我完成这个任务吗?

java pdf itext text-extraction
6个回答
29
投票
我是iText文本提取子系统的作者。 你需要做的是开发自己的文本提取策略(如果你看看

PdfTextExtractor.getTextFromPage

是如何实现的,你会发现你可以提供一个可插入的策略)。

如何确定列的开始和结束位置完全取决于您 - 这是一个困难的问题 - PDF 没有任何列的概念(哎呀,它甚至没有单词的概念 - 只是放在一起默认策略提供的文本提取非常棘手)。 如果您预先知道列在哪里,那么您可以在文本渲染侦听器回调上使用区域过滤器(iText 库中有用于执行此操作的代码,最新版本的 iText In Action 书中提供了详细的示例) .

如果您需要从任意数据中获取列,那么您需要完成一些算法工作(如果您能成功,我很乐意看一下)。 关于如何解决这个问题的一些想法:

    使用与默认文本提取策略(LocationAware...)中使用的算法类似的算法来获取单词和 X/Y 位置的列表(请务必考虑旋转角度)
  1. 对于每个单词,绘制一条贯穿页面整个高度的假想线。 扫描以相同 X 位置开始的所有其他单词。
  2. 扫描时,还要查找与 X 位置相交的单词(但不要从 X 位置开始)。 这将为您提供页面上列开始/停止 Y 位置的潜在位置。
  3. 一旦有了 X 和 Y 列,您就可以采用区域过滤方法
另一种可能同样可行的方法是分析绘制操作并寻找长水平线和垂直线(假设列以类似表格的格式划分)。 目前,iText 内容解析器没有这些操作的回调,但是可以毫无困难地添加它们。


1
投票
除非文件使用结构化内容,否则表格在 PDF 中不会以结构形式存在。你知道什么是PDF文件吗?我在

http://www.jpedal.org/PDFblog/?p=228 写了一篇博客文章解释文本提取问题


1
投票
您也可以尝试 PdfBox,但这一切都可以追溯到 PDF 中缺乏结构 - 它主要是用于显示的最终文件输出格式。


1
投票

PDFTextStream 就是其中之一!至少我能够识别列值。早些时候,我使用 iText 并陷入了定义策略的困境。很难。

此 api 通过放置更多空格来分隔列单元格。它是固定的。你可以放逻辑。 (iText 中缺少此内容)。

import com.snowtide.PDF; import com.snowtide.pdf.Document; import com.snowtide.pdf.OutputTarget; public class PDFText { public static void main(String[] args) throws java.io.IOException { String pdfFilePath = "xyz.pdf"; Document pdf = PDF.open(pdfFilePath); StringBuilder text = new StringBuilder(1024); pdf.pipe(new OutputTarget(text)); pdf.close(); System.out.println(text); } }
    

0
投票
您要从中提取的文件对于数据提取而言非常复杂。 有表格、图像、多个、列。 您将需要特殊的算法来确定读取顺序并处理表数据。

您想在这里实现什么目标? 您可以使用商业 OCR 引擎,让它完成所有艰苦的工作,然后处理数据。


0
投票
我知道我的回答有点晚了。但我使用以下代码来读取 PDF 文件中的某些页面。我在阅读列时没有任何问题,没有合并文本,每一列都与另一列分开打印。

/** * Get plain text from a specific page in a pdf file. * @param pdfPath * @return * @throws IOException */ public static String getPageContent(String pdfPath, int pageNumber) throws IOException { PdfReader reader = new PdfReader(pdfPath); StringWriter output = new StringWriter(); try { output.append(PdfTextExtractor.getTextFromPage(reader, pageNumber, new SimpleTextExtractionStrategy())); } catch (OutOfMemoryError e) { // TODO Auto-generated catch block e.printStackTrace(); } return output.toString(); }

如果您正在考虑提取页面的一部分,假设仅提取 1 列,那么您需要获取该列的尺寸。这仍然有点棘手,但如果您已经知道该列的开始文本(以估计宽度和高度的方式),您也许能够弄清楚这一点。这可以通过使用矩形区域来完成。请参阅下面的代码,如果我的点测量错误,抱歉。在下面的代码中,我尝试获取整个页面尺寸。

public static String getPageContent(String pdfPath, int pageNumber) throws IOException { PDDocument pdDoc = PDDocument.load(pdfPath); PDPage specPage = (PDPage)pdDoc.getDocumentCatalog().getAllPages().get( 0 ); PDFTextStripperByArea stripper = new PDFTextStripperByArea(); stripper.setSortByPosition( true ); float width = (specPage.getMediaBox().getHeight())*25.4f; float height = (specPage.getMediaBox().getWidth())*25.4f; Rectangle rect = new Rectangle( 0, 0, Math.round(width), Math.round(height)); stripper.addRegion( "class1", rect ); List allPages = pdDoc.getDocumentCatalog().getAllPages(); PDPage firstPage = (PDPage)allPages.get( pageNumber-1 ); stripper.extractRegions( firstPage ); return stripper.getTextForRegion( "class1" );

}

© www.soinside.com 2019 - 2024. All rights reserved.