java

java分析pdf文本段落

由于pdf使用坐标定位,pdf元素不像word那样有段落的概念,所以要提取pdf中的段落不是一件容易的事情。笔者通过不断尝试和优化,达到了一个比较理想的效果,根据文本的坐标以及文本间距判断一段文本和另一段文本是否是属于同一段。

效果图:

pdf-layout

核心代码如下:

 /**
     * 把同一块的文本分为一组 通过开始和接收位置的x坐标判断
     *
     * @param texts
     * @return 页面 - 该页的文本块
     */
    public static Map<Integer, List<PageBlockText>> groupByBlock(List<TextPosition> texts) {

        //分组 key 为pageNo-x-endX
        Map<Integer, List<PageBlockText>> pageGroup = new TreeMap<>();
        float rowH = 0;//同一段落行间距
        TextPosition preText = null;
        PageBlockText pageBlockText = null;
        for (TextPosition text : texts) {
            if (text.getText() == null || text.getText().isEmpty()) {
                continue;
            }
            Integer pageNo = text.getPageNo();
            List<PageBlockText> blockTexts = pageGroup.get(pageNo);
            if (blockTexts == null) { //新的一页
                blockTexts = new ArrayList<>();
                pageGroup.put(pageNo, blockTexts);

                //新的一块
                pageBlockText = new PageBlockText();
                pageBlockText.setPageNo(pageNo);
                pageBlockText.setX(text.getX());
                pageBlockText.setY(text.getY());
                pageBlockText.setEndX(text.getEndX());
                pageBlockText.setEndY(text.getEndY());

                pageBlockText.setBlock(1);
                pageBlockText.setTextPositionList(new ArrayList<>());
                pageBlockText.getTextPositionList().add(text);
                blockTexts.add(pageBlockText);

            } else { //和之前的是同一页
                boolean sameBlock = isSameBlock(preText, text, rowH);
                if (sameBlock) { //和前面一段是相同块
                    rowH = text.getY() - preText.getEndY();
                    if (rowH < 0) {
                        rowH = 0;
                    }
                    if (text.getX() < pageBlockText.getX()) {
                        pageBlockText.setX(text.getX());
                    }
                    if (text.getY() < pageBlockText.getY()) {
                        pageBlockText.setY(text.getY());
                    }
                    if (text.getEndX() > pageBlockText.getEndX()) {
                        pageBlockText.setEndX(text.getEndX());
                    }
                    if (text.getEndY() > pageBlockText.getEndY()) {
                        pageBlockText.setEndY(text.getEndY());
                    }

                    pageBlockText.getTextPositionList().add(text);

                } else { //不是相同块
                    rowH = 0; //归零
                    int preBlock = pageBlockText.getBlock();
                    //新建一块
                    pageBlockText = new PageBlockText();
                    blockTexts.add(pageBlockText);
                    pageBlockText.setPageNo(pageNo);

                    pageBlockText.setX(text.getX());
                    pageBlockText.setY(text.getY());
                    pageBlockText.setEndX(text.getEndX());
                    pageBlockText.setEndY(text.getEndY());

                    pageBlockText.setBlock(preBlock + 1);
                    pageBlockText.setTextPositionList(new ArrayList<>());
                    pageBlockText.getTextPositionList().add(text);

                }
            }
            preText = text;

        }

        //对每一页中的block排序(从左到右)
        for (Map.Entry<Integer, List<PageBlockText>> entry : pageGroup.entrySet()) {
            List<PageBlockText> list = entry.getValue();


            //插入排序
            int size = list.size();
            for (int i = 1; i < size; i++) {
                // 记录当前待插入的元素
                PageBlockText current = list.get(i);
                // 记录前一个元素的索引
                int j = i - 1;


                //
                while (j >= 0 &&
                        (
                                list.get(j).getX() > current.getEndX() ||  //current在j的左边
                                        (list.get(j).getY() > current.getEndY() && list.get(j).getEndX() > current.getX()) //current在j的上边
                        )
                ) {
                    // 将已排序序列中比当前待插入元素大的元素后移一位
                    list.set(j + 1, list.get(j));
                    j--;
                }
                // 将当前待插入的元素插入到正确的位置
                list.set(j + 1, current);
            }


        }


        return pageGroup;

    }

    /**
     * 跟前一块文本是否是属于同一块
     *
     * @param preText     前一块
     * @param currentText 当前块
     * @return
     */
    private static boolean isSameBlock(TextPosition preText, TextPosition currentText, float rowH) {
       
        return false;
    }

关于作者

程序员,软件工程师,java, golang, rust, c, python,vue, Springboot, mybatis, mysql,elasticsearch, docker, maven, gcc, linux, ubuntu, centos, axum,llm, paddlepaddle, onlyoffice,minio,银河麒麟,中科方德,rpm