总之
此问题的原因是,将提取的文本块展平为单个 String 以应用正则表达式的例程没有插入任何换行符指示符。因此,在String 中,一行的最后一个字母紧随其后的是下一行的第一个字母,它隐藏了单词边界。如果出现换行符,可以通过向String 添加适当的字符来修复此行为。
有问题的代码
将提取的文本块扁平化为单个String 的例程是包com.itextpdf.kernel.pdf.canvas.parser.listener 中的CharacterRenderInfo.mapString(List<CharacterRenderInfo>)。如果只是水平间隙,此例程会插入一个空格字符,但如果是垂直偏移,即换行符,它不会向生成 String 表示的 StringBuilder 添加任何额外内容:
if (chunk.sameLine(lastChunk)) {
// we only insert a blank space if the trailing character of the previous string wasn't a space, and the leading character of the current string isn't a space
if (chunk.getLocation().isAtWordBoundary(lastChunk.getLocation()) && !chunk.getText().startsWith(" ") && !chunk.getText().endsWith(" ")) {
sb.append(' ');
}
indexMap.put(sb.length(), i);
sb.append(chunk.getText());
} else {
indexMap.put(sb.length(), i);
sb.append(chunk.getText());
}
一个可能的解决办法
可以扩展上面的代码以在换行的情况下插入换行符:
if (chunk.sameLine(lastChunk)) {
// we only insert a blank space if the trailing character of the previous string wasn't a space, and the leading character of the current string isn't a space
if (chunk.getLocation().isAtWordBoundary(lastChunk.getLocation()) && !chunk.getText().startsWith(" ") && !chunk.getText().endsWith(" ")) {
sb.append(' ');
}
indexMap.put(sb.length(), i);
sb.append(chunk.getText());
} else {
sb.append('\n');
indexMap.put(sb.length(), i);
sb.append(chunk.getText());
}
此CharacterRenderInfo.mapString 方法仅从RegexBasedLocationExtractionStrategy 方法getResultantLocations()(包com.itextpdf.kernel.pdf.canvas.parser.listener)调用,并且仅用于提到的任务,即应用有问题的正则表达式。因此,使其能够正确识别单词边界不应该破坏任何东西,但确实应该被视为一种修复。
人们可能只考虑为换行符添加不同的字符,例如一个普通的空间' ',如果不想处理与水平间隙不同的垂直间隙。因此,对于一般修复,可以考虑将此字符作为策略的可设置属性。
版本
我使用 iText 7.1.4-SNAPSHOT 和 PDFSweep 2.0.3-SNAPSHOT 进行了测试。