使用pdfbox从.pdf文件中逐字提取文本

时间:2015-08-25 12:12:02

标签: pdf export-to-excel pdfbox text-extraction

我的目标是从.pdf文件中提取文本并将其写入Excel文件而不会丢失文本格式。在这一刻,我成功地用二维数组中的字体,大小和坐标逐字提取文本,但我有一点问题:同一行中的不同单词已组合成一个单词。

例如:

020 | 0542 | CD45

它将用同一个词提取:0200542CD45

我找不到我的错误在哪里。我需要你的帮助。

这是我的代码:

public class PrintTextLocations extends PDFTextStripper {

    public static StringBuilder tWord = new StringBuilder();
    public static String[][] coordTab;
    public static int p = 0;
    public static String seek;
    public static String[] seekA;
    public static List<String> wordList = new ArrayList();
    public static boolean is1stChar = true;
    public static boolean lineMatch;
    public static int pageNo = 1;
    public static double lastYVal;

    public PrintTextLocations() throws IOException {
        super.setSortByPosition(true);
    }

    public static void main(String[] args) throws Exception {
        PDDocument document = null;
        PDFTextParser pdftext = new PDFTextParser();
        String file_name = "d:/test.pdf";
        seekA = pdftext.pdftoText(file_name).split(" ");
        seek = pdftext.pdftoText(file_name);
        coordTab = new String [seekA.length*2][6];
        try {
            File input = new File(file_name);
            document = PDDocument.load(input);
            if (document.isEncrypted()) {
                document.decrypt("");
            }
            PrintTextLocations printer = new PrintTextLocations();
            List allPages = document.getDocumentCatalog().getAllPages();

            for (int i = 0; i < allPages.size(); i++) {
                PDPage page = (PDPage) allPages.get(i);
                PDStream contents = page.getContents();
                if (contents != null) {
                     printer.processStream(page, page.findResources(), page.getContents().getStream());
                }
                pageNo += 1;
            }
        } finally {
            if (document != null) {
                for (int k = 0; k<= p;k++){
                    System.out.println(k+" : "+coordTab[k][0]+" | "+coordTab[k][1]+" | "+coordTab[k][2]+" | "+coordTab[k][3]+" | "+coordTab[k][4]+" | "+coordTab[k][5]);
                }           
                myxls.close();
                document.close();
            }
        }
    }

    @Override
    protected void processTextPosition(TextPosition text) {
        String tChar = text.getCharacter();
        String REGEX = "'' ";
        char c = tChar.charAt(0);
        lineMatch = matchCharLine(text);
        if (!Character.isWhitespace(c)) {
            if ((!is1stChar) && (lineMatch == true)) {
                appendChar(tChar);
            } else if (is1stChar == true) {
                setWordCoord(text, tChar);
            }
        } else {
            endWord();
        }
    }

    protected void appendChar(String tChar) {
        tWord.append(tChar);
        coordTab[p][3] = String.valueOf(tWord);
        is1stChar = false;
    }

    protected void setWordCoord(TextPosition text, String tChar) {
        tWord.append(tChar);

        coordTab[p][0] = ""+ pageNo;
        coordTab[p][1] = ""+ roundVal(Float.valueOf(text.getX()));
        coordTab[p][2] = ""+ roundVal(Float.valueOf(text.getY()));
        coordTab[p][3] = String.valueOf(tWord);
        coordTab[p][4] = ""+text.getFontSize();
        coordTab[p][5] = ""+text.getFont().getBaseFont();

        is1stChar = false;
    }

    protected void endWord() {
        String newWord = tWord.toString().replaceAll("[^\\x00-\\x7F]", "");
        String sWord = newWord.substring(newWord.lastIndexOf(' ') + 1);
        if (!"".equals(sWord)) {
            if (Arrays.asList(seekA).contains(sWord)) {
                wordList.add(newWord);
            } else {
                wordList.add(newWord);
            }
        }
        tWord.delete(0, tWord.length());
        is1stChar = true;
        p++;
    }

    protected boolean matchCharLine(TextPosition text) {
        Double yVal = roundVal(Float.valueOf(text.getY()));
        if (yVal.doubleValue() == lastYVal) {
            return true;
        }
        lastYVal = yVal.doubleValue();
        endWord();
        return false;
    }

    protected Double roundVal(Float yVal) {
        DecimalFormat rounded = new DecimalFormat("###.##");
        String st = rounded.format(yVal);
        Double yValDub = Double.parseDouble(st.replace(",", "."));
        return yValDub;
    }
}

1 个答案:

答案 0 :(得分:0)

缺少的空格

这方面的错误是你假设单词之间的间隙是由空字符提取的空格字符创建的。

不一定是这种情况!

这些间隙也可以通过显式转发x位置来创建。

由于您只查看文本来源的y坐标(TextPosition.getY()中的matchCharLine),但忽略其x坐标(TextPosition.getX()),您会错过这些间隙。

另一个问题

您假设检索TextPosition个实例的顺序是&#34;正确&#34;顺序。

不一定是这种情况!

您的文字的字形可能会以随机顺序绘制,因此您可能会以随机顺序接收它们。

很少看到完全随机的顺序,但每隔一段时间就会使用一定程度的重新排序。

怎么做

PDFBox PDFTextStripper类实际上已经使用了经过良好测试的例程来添加间隙指示的空格以及对无序字形进行排序。但是,通过覆盖processTextPosition,您可以阻止使用该代码。

因此,您不应该替换processTextPosition方法,而应覆盖writeString(String, List<TextPosition>)writeWordSeparator()方法。

对于字形的自动排序,只需使用setSortByPosition(true)