我知道这可能有点不寻常,但我想知道PDF文档(字节数组)是否包含特定的文本。我使用iText库v2.1.7自己在Java中创建文档,它生成符合PDF 1.4规范的文档。
我最初的天真尝试是这样的:
byte[] target = "the target text".getBytes("UTF-8");
int index = Bytes.indexOf(pdfBytes, target); // Guava lib
System.out.println( index ); // always -1 (not found)
我对这些类型的文档如何编码以了解我需要做什么并不是很了解。我想我真正需要知道的是当我转换为字节时,我需要在目标文本上使用什么样的编码,以便它与PDF使用的匹配。
我创建了一个小样本PDF文档,除了包含单词one two three four five
的短语外,其他任何内容都没有。如果我cat
Linux终端中的文件(或使用vim
查看它),那就是PDF文件的内容:
%PDF-1.4
%����
2 0 obj
<</Filter/FlateDecode/Length 71>>stream
x�+�r
�24U�02I�2P0Q�n�
�F
!i\�y�
%��
%E��
i��E
i�e��!Y0Ů!\�\���
endstream
endobj
4 0 obj
<</Contents 2 0 R/Type/Page/Resources<</ProcSet [/PDF /Text /ImageB /ImageC /ImageI]/Font<</F1 1 0 R>>>>/Parent 3 0 R/MediaBox[0 0 595 842]>>
endobj
1 0 obj
<</Subtype/Type1/Type/Font/BaseFont/Helvetica/Encoding/WinAnsiEncoding>>
endobj
3 0 obj
<</Kids[4 0 R]/Type/Pages/Count 1/ITXT(2.1.7)>>
endobj
5 0 obj
<</Type/Catalog/Pages 3 0 R>>
endobj
6 0 obj
<</ModDate(D:20171216101023Z)/CreationDate(D:20171216101023Z)/Producer(iText 2.1.7 by 1T3XT)>>
endobj
xref
0 7
0000000000 65535 f
0000000309 00000 n
0000000015 00000 n
0000000397 00000 n
0000000152 00000 n
0000000460 00000 n
0000000505 00000 n
trailer
<</Info 6 0 R/ID [<9e1d205d229e3d1b5b56354a7da26844><7bf1bdf9e8d048c5795c7785954d9360>]/Root 5 0 R/Size 7>>
startxref
615
%%EOF
其中一些字符编码在复制和粘贴中没有正确翻译,因此如果您复制并保存您在那里看到的内容,您将获得损坏的PDF。 Here's a link到该PDF的副本。
我尝试将目标字符串编码为各种编码,例如CP-1252和WinAnsiEncoding,但这些是无法识别的字符集。
我没想到这会给我带来很多麻烦,但我还没有弄清楚如何做到这一点。我确实有一个解决方法可以获得相同的结果,但它是一个专门用于iText库的解决方案,即不是在PDF字节数组中搜索文本的通用解决方案。
如果我使用iText来解析我想要搜索的字节数组,我可以迭代PDF的每一页并提取文本:
private static boolean doesPDFContain(byte[] pdf, String text) throws Exception {
PdfReader reader = new PdfReader(pdf);
int numPages = reader.getNumberOfPages();
PdfTextExtractor extractor = new PdfTextExtractor(reader);
for (int i=1; i<=numPages; i++) {
if ( extractor.getTextFromPage(i).contains(text) ){
return true;
}
}
return false;
}
我仍然有兴趣听听是否有可能做我最初尝试的事情。
答案 0 :(得分:4)
有很多原因可以解释为什么你的天真方法---只是在特定的编码中寻找文本 - 通常是行不通的。
您要查找的文字,屏幕上显示的文字,是由某些内容流中的文字绘图说明绘制的。 (让我们忽略图形看起来像文本但是使用矢量或位图图形命令以及丢失或不准确的字体编码信息绘制的情况。)
您要查找的文字不一定是由一条指令绘制的。例如,文本“Hello”可能使用两个连续的命令编写:
(Hel) Tj (lo) Tj
不同的命令甚至不需要在内容流中互相跟随,它们可能会分散在其中。
PDF中的每种字体都可以对其字符串使用不同的编码,这些编码甚至不需要是标准编码,它们可能是PDF创建程序即时创建的ad-hoc编码。 / p>
内容流可以(并且通常确实)需要用于解码的过滤器,例如,在上面的PDF中,对象2中的内容流需要 FlateDecode 过滤(基本上:解压缩)。
PDF可以加密(在这种情况下,更具体地说,字符串和流是加密的);甚至可以在PDF查看器中打开而无需进一步操作的PDF也可以使用默认密码加密(此技术用于编码权限)。
因此,要检查内容流的内容,您可能需要
在这个字符串中,您最终可以以天真的方式搜索文本。