如何从 Swift 中的 PDF 中获取所有文本?

How can I get all text from a PDF in Swift?

我有一个 PDF 文档,想提取其中的所有文本。 我尝试了以下方法:

import Quartz

let url = NSBundle.mainBundle().URLForResource("test", withExtension: "pdf")
let pdf = PDFDocument(URL: url)
print(pdf.string())

它确实获取了文本,但是与在 Adob​​e 中打开 PDF 相比,提取的行的顺序完全混乱,编辑 Select 全部,复制,粘贴!

如何在 Swift 中获得与打开 PDF 相同的结果,Select 全部,Copy/Paste!?

不幸的是,这是不可能的。
至少不是没有你的一些主要工作。对于所有 pdf 来说,一般情况下肯定是不可能的。

PDF(通常)是一条单行道。
创建它们是为了在每个系统上以相同的方式显示文本而没有任何区别,并且打印机可以打印文档而无需打印机知道所有字体和内容。

提取文本并非易事,仅适用于基本图像 pdf 附有文本(不必如此)的某些 PDF。 PDF 中存在的所有文本信息都与位置信息相结合,以确定要显示的位置。

如果您在 PDF 中显示 table,其中左列包含条目名称,右行包含其内容,那么这两列都可以表示为完全不同的文本块只有 看起来 彼此之间有一些 link,因为它们彼此相邻。

框架/您的代码必须做的是确定视觉上 linked 的文本部分在逻辑上也 linked 并且属于一起。这(还)是不可能的。你我之所以能看懂PDF并能分组,是因为在某些领域我们的大脑还是远比电脑好

最后说明,因为它可能会引起混淆:Adobe 和 Apple 当然也有可能已经做了一些这种分组并取得了不错的结果,但它仍然不完美。我刚刚测试的 PDF 在通过 Mac 预览提取文本后被严重破坏了。

如果您只需要文本内容:

  extension String
{
    func readPDF() -> String
    {
        let path = "\(self)"
        let url = URL(fileURLWithPath: path)
        let pdf = PDFDocument(url: url)
        return pdf!.string!
    }
}

Apple 的 PDFDocument class 文档说该字符串是 "a convenience method, equivalent to creating a selection object for the entire document and then invoking the PDFSelection class’s string method."

所以你应该得到与在预览中复制和粘贴相同的结果。

Adobe 的 Acrobat 可能会使用其他一些例程来创建逻辑上更有用的流程,但您无法在 MacOS 中以编程方式访问它。

这里有一个使用 PDFKit 的选项:

import Cocoa
import Quartz

func pdfToText(fromPDF: String) -> String {
    let urlPath = Bundle.main.url(forResource: fromPDF, withExtension: "pdf")
    let docContent = NSMutableAttributedString()
    if let pdf = PDFDocument(url: urlPath!) {
        let pageCount = pdf.pageCount

        for i in 1 ..< pageCount {
            guard let page = pdf.page(at: i) else { continue }
            guard let pageContent = page.attributedString else { continue }
            docContent.append(pageContent)
        }
    }

    return docContent.string
}

let pdfString = pdfToText(fromPDF: "documentName")

这使您可以选择将 PDF 内容作为属性字符串获取。如果您只是在寻找纯文本,您可以像我在上面的示例中所做的那样,通过将 .string 附加到结果来获得它。

比照。 Paul Hudson's snippet

我做到了。有了这个:

if let pdf = PDFDocument(url: url) {
    let pageCount = pdf.pageCount
    let documentContent = NSMutableAttributedString()

    for i in 1 ..< pageCount {
        guard let page = pdf.page(at: i) else { continue }
        guard let pageContent = page.attributedString else { continue }
        documentContent.append(pageContent)
    }
}

希望对您有所帮助。