6

我有一个包含 utf-8 字符(İ、ğ、ı 和阿拉伯字母等)的 pdf 文件。如何解析这个文件?
我使用 itext 和 pdfBox,但我看到的是“çekti¤i k夛da”而不是“çektiği kağıda”。我该如何解决这个问题?

4

4 回答 4

2

由于尚未提供样本,我自己创建了阿拉伯语测试数据(实际上,我从 itext-questions 邮件列表中的一些帖子中借用了用于创建测试数据的代码)和一个解析这些数据的测试:

package itext.parsing;

import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStream;

import com.itextpdf.text.Document;
import com.itextpdf.text.DocumentException;
import com.itextpdf.text.Font;
import com.itextpdf.text.Paragraph;
import com.itextpdf.text.Phrase;
import com.itextpdf.text.pdf.BaseFont;
import com.itextpdf.text.pdf.PdfPCell;
import com.itextpdf.text.pdf.PdfPTable;
import com.itextpdf.text.pdf.PdfReader;
import com.itextpdf.text.pdf.PdfWriter;
import com.itextpdf.text.pdf.parser.PdfTextExtractor;

import junit.framework.TestCase;

public class TextExtractingArabic extends TestCase
{
    public void testExtractArabicChars() throws DocumentException, IOException
    {
        createTestFile(TEST_FILE);

        PdfReader reader = new PdfReader(TEST_FILE.toString());
        String text = PdfTextExtractor.getTextFromPage(reader, 1);
        for (char c: text.toCharArray())
        {
            int i = c<0 ? Integer.MAX_VALUE + c : c;
            System.out.print("\\u");
            System.out.print(Integer.toHexString(i));
        }
    }

    void createTestFile(File file) throws DocumentException, IOException
    {
        Document document = new Document();
        OutputStream os = new FileOutputStream(file);
        PdfWriter.getInstance(document, os);
        document.open();

        BaseFont bfArialUni = BaseFont.createFont("C:\\Windows\\Fonts" + "\\ARIALUNI.TTF",
                                            BaseFont.IDENTITY_H, BaseFont.EMBEDDED);            
        Font fontArialUni = new Font(bfArialUni, 12f);
        Phrase myPhrase = new Phrase(LAWRENCE_OF_ARABIA, fontArialUni);

        PdfPTable table = new PdfPTable(1);
        PdfPCell cell = new PdfPCell(new Paragraph(myPhrase));
        cell.setColspan(3);
        cell.setPaddingRight(15f);
        cell.setBorder(PdfPCell.NO_BORDER);
        cell.setRunDirection(PdfWriter.RUN_DIRECTION_RTL);
        table.addCell(cell);

        document.add(table);
        document.close();
        os.close();
    }

    final static File TEST_FILE = new File("arabic-test.pdf");
    final static String LAWRENCE_OF_ARABIA =
        "\u0644\u0648\u0631\u0627\u0646\u0633\u0627\u0644\u0639\u0631\u0628";
}

字符串 LAWRENCE_OF_ARABIA 在语音上有点接近阿拉伯的劳伦斯。

文本的输出是:

\ufe8f\ufeae\ufecc\ufedf\ufe8e\ufeb4\ufee7\ufe8d\ufead\ufeee\ufedf

虽然这与输入不同,但快速查看 unicode 表会发现输入来自 Unicode Range“Arabic”,输出来自 Unicode Range“Arabic Presentation Forms-B”。此外,输出是从左到右的,而输入是从右到左的。

我自己不懂阿拉伯语,因此不能说输出有多准确,但解析的字符肯定来自适当的 Unicode 范围。

据可以知道,在没有访问原始海报的情况下可以使用原始海报,因此,问题似乎不在于解析,而在于正确使用解析器的输出。

于 2012-10-22T08:26:38.480 回答
1

正如 Bobrovsky 提到的,它可能看起来不错,而底层编码并不完全正确。在 PDF 查看器中看起来像 X 的字形可能不会在内部编码为字符 X。您可以通过将文本从 Adob​​e PDF Reader 复制粘贴到支持该字符集的文本编辑器来轻松测试这一点。如果复制粘贴OK,则可以提取,否则不能提取(无需采取手动措施,例如自定义映射)。

于 2012-10-21T14:41:26.590 回答
0

有时 PDF 是使用在实际字体字节和描述字体的 PDF 结构中指定的不同编码生成的。

在这种情况下,文本显示得很好,但可能无法正确提取。我经常在西欧语言中看到这种情况。

为了克服这个问题,Docotic.Pdf 库会自动检测是否更喜欢字体文件编码。

这是显示不同 PDF 文本提取选项的文章。

免责声明:我为图书馆的供应商工作。

于 2012-10-20T22:45:58.243 回答
0

为每个字符调用下面的函数 escape(String char)。它将返回 UTF-8 字符。此功能也来自 PDFBox。

    private String escape(String chars)
{
    StringBuilder builder = new StringBuilder(chars.length());
    for (int i = 0; i < chars.length(); i++)
    {
        char c = chars.charAt(i);
        // write non-ASCII as named entities
        if ((c < 32) || (c > 126))
        {
            int charAsInt = c;
            builder.append("&#").append(charAsInt).append(";");
        }
        else
        {
            switch (c)
            {
            case 34:
                builder.append("&quot;");
                break;
            case 38:
                builder.append("&amp;");
                break;
            case 60:
                builder.append("&lt;");
                break;
            case 62:
                builder.append("&gt;");
                break;
            default:
                builder.append(String.valueOf(c));
            }
        }
    }
    return builder.toString();
} 

这是一个类似的问题。请看一看。

于 2012-11-05T07:51:43.590 回答