我正在使用PDFBox从PDF文件中提取文本。我面临的一个问题是:PDFBox将主要内容与我想忽略的PDF页脚/标题部分混合在一起。
我被告知以下代码会有所帮助:
Rectangle rec = new Rectangle();
# init rec...
PDFTextStripperByArea stripper = new PDFTextStripperByArea();
stripper.addRegion("cropbox", rec);
stripper.setSortByPosition(true);
有人可以告诉我stripper.setSortByPosition(true)
究竟是什么意思吗?我阅读了文档,但我仍感到困惑:
当我使用上面的代码从PDF文件中提取文本时,我收到了以下错误:
Exception in thread "main" java.lang.IllegalArgumentException:
Comparison method violates its general contract!
at java.util.TimSort.mergeLo(TimSort.java:747)
at java.util.TimSort.mergeAt(TimSort.java:483)
at java.util.TimSort.mergeCollapse(TimSort.java:408)
at java.util.TimSort.sort(TimSort.java:214)
at java.util.TimSort.sort(TimSort.java:173)
at java.util.Arrays.sort(Arrays.java:659)
at java.util.Collections.sort(Collections.java:217)
at org.apache.pdfbox.util.PDFTextStripper.writePage(PDFTextStripper.java:565)
at org.apache.pdfbox.util.PDFTextStripperByArea.writePage(PDFTextStripperByArea.java:190)
at org.apache.pdfbox.util.PDFTextStripper.processPage(PDFTextStripper.java:457)
at org.apache.pdfbox.util.PDFTextStripperByArea.extractRegions(PDFTextStripperByArea.java:153)
有人可以帮我解决这个问题吗?
PS:供您参考,以下是setSortByPosition
的文档:
PDF文件中文本标记的顺序可能与它们在屏幕上直观显示的顺序不同。例如,PDF编写器可能会按字体写出所有文本,因此所有粗体或更大的文本都会写出,然后再进行第二遍并写出正常文本。
默认设置是不按位置排序。
PDF编写者可以选择以不同的顺序编写每个字符。默认情况下,由于性能原因,PDFBox在处理之前不会对文本标记进行排序。
PPS: @Tilman Hausherr:这是一个已知问题:-(
请参阅:issues.apache.org/jira/browse/PDFBOX-1512
更新: 避免这些例外的一种可能方式是:
System.setProperty("java.util.Arrays.useLegacyMergeSort", "true");
答案 0 :(得分:1)
我查看了源代码,发现他们的TextPositionComparator
(Comparator
用于排序文本位置)似乎违反了合同。 (在这种情况下,TimSort [java 7+]可能会抛出异常; PDFBox似乎仍然与java 4兼容,并且他们计划更新到Java 6 for version 2.0,因此它们可能不是最新的...)
您最好告知开发人员(PDFBox)该错误。但是,您可以下载源代码并自行更改比较器。我很确定错误在TextPositionComparator
的第63行(修订版1575836)中。
他们允许y值有一些容差。您可以提出违反Comparator
界面合同一部分的TextPosition:
实现者还必须确保关系是传递的:((compare(x,y)> 0)&&(compare(y,z)> 0))暗示比较(x, Z)> 0
要显示违反此条件的行为:选择TextPosition.getYDirAdj()
(posYBottom)为0,0.05和0.11,并确保第64,65行中的条件为false并且您可以通过正确选择x位置来选择3个compare
结果中的1个。
答案 1 :(得分:0)
此问题与Collections.sort(List<E> list)
方法有关,该方法已被JDK7取代。对于进一步的信息看
here:
区域:API:实用程序概要:更新了阵列和的排序行为 集合可能抛出IllegalArgumentException描述: java.util.Arrays.sort使用的排序算法和(间接)by java.util.Collections.sort已被替换。新的排序 如果检测到,实现可能会抛出IllegalArgumentException 违反可比较合同的可比较。以前的 实施默默地忽略了这种情况。如果是以前的 行为是理想的,你可以使用新的系统属性, java.util.Arrays.useLegacyMergeSort,用于恢复以前的mergesort 行为。不相容性:行为RFE:6804124
要解决问题,请使用该代码:
System.setProperty("java.util.Arrays.useLegacyMergeSort", "true");
这会将排序算法设置为JDK7之前的行为。为我工作得很好......
答案 2 :(得分:0)
答:我对PDF格式的理解是它由字符组成(仅在此处讨论文本),使用相对于页面左下角的坐标精确放置。 PDF创作时的这些字符,不必插入一个不间断的序列,从左到右,从上到下插入。因此,通过将SortByPosition设置为true,您可以告诉PdfBox尝试使用顺序对字符进行排序,这些字符在屏幕上的显示方式与PDF文件中字符的顺序相反。