我有一个包含 utf-8 字符(İ、ğ、ı 和阿拉伯字母等)的 pdf 文件。如何解析这个文件?
我使用 itext 和 pdfBox,但我看到的是“çekti¤i k夛da”而不是“çektiği kağıda”。我该如何解决这个问题?
4 回答
由于尚未提供样本,我自己创建了阿拉伯语测试数据(实际上,我从 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 范围。
据可以知道,在没有访问原始海报的情况下可以使用原始海报,因此,问题似乎不在于解析,而在于正确使用解析器的输出。
正如 Bobrovsky 提到的,它可能看起来不错,而底层编码并不完全正确。在 PDF 查看器中看起来像 X 的字形可能不会在内部编码为字符 X。您可以通过将文本从 Adobe PDF Reader 复制粘贴到支持该字符集的文本编辑器来轻松测试这一点。如果复制粘贴OK,则可以提取,否则不能提取(无需采取手动措施,例如自定义映射)。
有时 PDF 是使用在实际字体字节和描述字体的 PDF 结构中指定的不同编码生成的。
在这种情况下,文本显示得很好,但可能无法正确提取。我经常在西欧语言中看到这种情况。
为了克服这个问题,Docotic.Pdf 库会自动检测是否更喜欢字体文件编码。
这是显示不同 PDF 文本提取选项的文章。
免责声明:我为图书馆的供应商工作。
为每个字符调用下面的函数 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(""");
break;
case 38:
builder.append("&");
break;
case 60:
builder.append("<");
break;
case 62:
builder.append(">");
break;
default:
builder.append(String.valueOf(c));
}
}
}
return builder.toString();
}
这是一个类似的问题。请看一看。