2018-09-26


难度 中等

2018-09-25

pdf解析

根据坐标

根据坐标来判断表格,主要是根据坐标的对应关系,而坐标的对应关系最终落实在单元格起始和结束。

总的来说,表格分为左对齐,右对齐和居中对齐,对于这三种情况都可以归纳为起点坐标相同或者终点坐标相同。

或者,另一个层面来说,是单元格个数相同,且对应单元格的距离相等。即一旦出现超过两行单元格个数相同,或者超过两行(每行每个)单元格起始坐标或结束坐标相同,即将其初步判断为表格。

即,先数个数,再算起始坐标,以及宽度。

pdf解析思路整理

先将pdf分解,解析到每一个字符,该节点携带了确定该字符的所有信息,(此处图片无法解析)。

每一个字符都携带了其必须的信息后,对其进行建模。

建模——起点+宽度+高度+字符模型

如前所述,pdf里的任何对象都是此模型,该模型具有通用性。

假设

假设1——行划分节点正确

假设对每一页pdf的每一行的节点划分都正确,具体为节点个数正确、节点起始坐标、高度、宽度、正确。

假设2——单元格规整

假设单元格规整,即单元格不存在跨行跨列,且每一行个数相同。

实际情况

1.并不是每一行的节点划分都正确。
2.并不是所有行都具有相同的节点数。
3.真正规整的表格较少,绝大多数存在跨行跨列。

整合折中

<table><tr><td bgcolor="Khaki">
但一个表格中至少有相连两行节点数相同,也不存在跨行跨列。
这将作为先判断表格中间行的依据。</td></table>

判断表格

第一遍先计算节点数,当节点数符合条件,计算距离。当两者均满足条件时,确定表格,然后再根据起始点和距离去寻找表格边框。

pdf解析

最终得到page,其内含有三个对象,代码如下:

//存放不根据表格线解析的表格所在的行索引
List<int []> form=new ArrayList<int[]>();
//存放根据表格线解析的表格信息
List<Form> forms=new ArrayList<Form>();
//存放所有的文本内容
List<TextRow> content=new ArrayList<TextRow>();

static关键字(修饰方法时方便在没有创建对象的情况下来进行调用)

static方法

static方法就是没有this的方法。在static方法内部不能调用非静态方法,反过来是可以的。而且可以在没有创建任何对象的前提下,仅仅通过类本身来调用static方法。这实际上正是static方法的主要用途。

static方法不依赖于任何对象就可以进行访问,即非static方法需要先建一个对象才可以进行访问。在static方法中不能访问类的非static成员变量和非static方法,因为非static方法/变量都必须依赖具体的对象才能被调用。但在非static成员方法中可以访问static方法/变量。

static变量

static变量被所有的对象所共享,在内存中只有一个副本,它当且仅当在类初次加载时会被初始化。

final关键字

java中,final关键字可以用来修饰类、方法和变量(包括成员变量和局部变量)。

修饰类

final修饰类,表示这个类不能被继承。

修饰方法

使用final方法的原因有两个。第一个原因是把方法锁定,以防任何继承类修改它的含义;第二个原因是效率。在早期的Java实现版本中,会将final方法转为内嵌调用。但是如果方法过于庞大,可能看不到内嵌调用带来的任何性能提升。在最近的Java版本中,不需要使用final方法进行这些优化了。

因此,只有在想明确禁止该方法在子类中被覆盖的情况下才将方法设置为final的。

注:类的private方法会隐式地被指定为final方法。

2018-09-27

java abstract关键字

抽象方法

1、从上面的例子中我们可以看到抽象方法跟普通方法是有区别的,它没有自己的主体(没有{}包起来的业务逻辑),跟接口中的方法有点类似。所以我们没法直接调用抽象方法

2、抽象方法不能用private修饰,因为抽象方法必须被子类实现(覆写),而private权限对于子类来说是不能访问的,所以就会产生矛盾

3、抽象方法也不能用static修饰,试想一下,如果用static修饰了,那么我们可以直接通过类名调用,而抽象方法压根就没有主体,没有任何业务逻辑,这样就毫无意义了。

抽象类

1、用abstract关键字来表达的类,其表达形式为:(public)abstract class 类名{}

2、抽象类不能被实例化,也就是说我们没法直接new 一个抽象类。抽象类本身就代表了一个类型,无法确定为一个具体的对象,所以不能实例化就合乎情理了,只能有它的继承类实例化。

3、抽象类虽然不能被实例化,但有自己的构造方法。

4、抽象类与接口(interface)有很大的不同之处,接口中不能有实例方法去实现业务逻辑,而抽象类中可以有实例方法,并实现业务逻辑,比如我们可以在抽象类中创建和销毁一个线程池。

5、抽象类不能使用finally关键字修饰,因为finally修饰的类是无法被继承,而对于抽象类来说就是需要通过继承去实现抽象方法,这又会产生矛盾。

抽象类与抽象方法的关联

如果一个类中至少有一个抽象方法,那么这个类一定是抽象类,但反之则不然。也就是说一个抽象类中可以没有抽象方法。这样做的目的是为了此类不能被实例化。

如果一个类继承了一个抽象类,那么它必须全部覆写抽象类中的抽象方法,当然也可以不全部覆写,如果不覆写全部抽象方法则这个子类也必须是抽象类。

java注解

Java中的注释主要有以下三种:

  • Override
  • Deprecated
  • SuppressWarning

注释是java代码的元数据(所谓元数据,就是数据的数据。也就是说,元数据存在的意义,就是为了描述数据)。

Override是用来标识当前的方法,是否覆盖了它的父类中的方法。
Deprecated用来标记过时的元素。
SuppressWarning用来阻止警告。

<T extends Comparable<? super T\>\>

public static <T extends Comparable<? super T>> void sort(List<T> list) {
    list.sort(null);
}

能调用sort方法进行排序,list中的元素必须是实现了Comparable接口的类或者其子类,通过<T extends Comparable<? super T\>\>来进行限定。

Java采取的是类型擦除的方法来实现泛型,并通过extends和super关键字来约束泛型的上界和下界。

  • extends关键字用于确定泛型的上界,<A extends B\>表示类B或者其子类。

  • super关键字用于确定泛型的下界,<A super B\>表示类B或者其父类,一直到Object。?则是一个通配符。

<T extends Compatable<? super T\>\>表示了上界为实现了Comparable接口的类,<? super T\>则表示实现Comparable接口的类的子类也可以,从而确定下界

2018-09-28

pdfbox解析说明

该项目为pdf无表格线解析,具体为将pdf文件转换为XML格式,方便数据入库。

该项目只提取pdf数据,不对表格进行识别。即除了过滤掉部分多余数据外,保留源文件的所有信息。

该项目最终输出XML文件,方便下游识别表格时对数据的读取。

重点

所需要的数据主要在表格中,具体表现为:

  • 資產負債表(资产负债表)
  • 利潤表(利润表)
  • 現金流量表(现金流量表)
  • 財務報表(财务报表)
  • 股東權益變動表(股东权益变动表)

即主要问题转换为对表格的识别判断以及一些附加数据,附加数据主要包括

  • 表格名称
  • 表格发布的时间日期

处理

1.与表格有关的数据必须保留

  • 表格名称
  • 表格发布的时间日期
  • 表的具体内容

以上数据不能有任何缺失

2.部分多余数据必须删除

1.页眉

2.页脚

3.页码

4.下划线

操作

综上,主要涉及两部分操作:

1.对于需要保留的数据,需要 正确划分节点

2.正确识别要删除的数据,不能误删

实现

采用pdfbox的框架解析出字符串后,再对字符串进行上述的处理。

pdfbox解析字符串

pdfbox解析的主要类是PDFTextStripper,需要对其中的writeString方法进行重写,重点处理对象为List<TextPosition> textPositions,具体如下:

public class TextPositonExtracter extends PDFTextStripper {
     @Override
    protected void writeString(String text, List<TextPosition> textPositions) throws IOException {
        //textPosition中存放了pdf中每一个字符的坐标,内容,高度,宽度
        for(TextPosition textPosition:textPositions){
            //具体的处理逻辑
            //包括如何划分节点,如何舍弃多余数据
        }
    }
}

字符识别节点及删除多余数据

目前的节点识别主要包括以下几点:

1.下划线直接删除

2.根据空格和距离划分节点

具体为计算第一个空格和最后一个空格的距离,设定一个阀值作为判别依据。

3.特殊标点符号直接处理

如顿号、冒号、括号直接合并。

2018-09-29

pdf解析维护、调整、优化

到目前为止,会出现问题的也只有三个方面:

  • 节点划分
  • 表格缺失
  • 页脚页码未去除

节点划分出现问题解决方法

1.特殊标点符号划分基本不会有问题;

2.节点划分一个重要参数就是字符阀值上限,该值是划分节点的主要依据。

该值在TextPositonExtracte类中定义。

//部分文档解析会误把两个单元格的内容合并到一起,同一个单元格里面内容的最大距离
//目前调整为14,后续若其他方法无法解决节点划分问题时可对其进行修改
private static final int CHARTHRESHOLD = 14;//20;

表格名称误删除问题解决

查看表名称是否在页的顶部,同时查看表名称的关键字是否包含在用于判断的正则表达式中。 对于表名称主要使用TextPositonExtracte类中的isSpecialChinese进行匹配,主要代码如下:

//可将新的表关键字加入到该匹配序列解决
 Pattern isSpecialChinese=Pattern.compile("^.*表|^.*損益.*|^.*收益.*|^.*全面.*|^.*財務.*|^.*變動.*|^.*损益.*|^.*收益.*|^.*财务.*|^.*資産.*|"
            + "^.*綜合.*|^.*簡明.*|簡|明|綜|合|損|益|及|其|他|全|面|收|財|務|狀|況|權|變|動|現|金|流|量|简|"
            + "明|综|财|务|状|况|损|现|权|股|变|动|資|産|產|利|潤|润|併|負|債|東|截|止|年|月|日|[0-9]|料|本|东");

页脚页码未删除

删除页脚主要判断每一页底部的三行,即筛选出三个最大的Y坐标,对这三个坐标内的字符进行判别。

代码方法为Pragrom类的RemoveFooter。

java访问权限控制

对于类的成员而言,其能否被其他类所访问,取决于该成员的修饰词;而对于一个类而言,其能否被其他类所访问,也取决于该类的修饰词。在Java中,类成员访问权限修饰词有四类:private,无(包访问权限),protected 和 public,而其中只有包访问权限和public才能修饰一个类(内部类除外)。具体如下:

  • public :被public修饰的类成员能被所有的类直接访问
  • private:被public修饰的类成员只能在定义它的类中被访问,其他类都访问不到。特别地,我们一般建议将成员变量设为private的,并为外界提供 getter/setter 去对成员变量进行访问,这种做法充分体现了Java的封装思想;
  • 包访问权限:包访问权限就是Java中的默认的权限,具有包访问权限的类成员只能被同一包中的类访问

protected关键字

  • 基类的protected成员是包内可见的,并且对子类可见;
  • 若子类与基类不在同一包中,那么在子类中,子类实例可以访问其从基类继承而来的protected方法,而不能访问基类实例的protected方法。

文章作者: growdu
版权声明: 本博客所有文章除特別声明外,均采用 CC BY 4.0 许可协议。转载请注明来源 growdu !
  目录
分类导航
随笔2 AI27 算法1 计算机基础13 博客搭建7 ChatGPT2 集群63 计算机通信1 数据库34 数据库深入80 DPDK26 Docker11 Elasticsearch4 编辑工具4 FAQ1 Go Web1 hometown2 编程语言16 网络9 OPC1 Linux38 openGauss4 页面12 PostgreSQL54 程序员自我修养1 协议11 成长之路1 stock1 存储5 工具20 VPP18 视频作品1 Vue13 Web1 代码示例11 数据库15 BenchmarkSQL1 PostgreSQL 源码修炼之路14
最热文章
1
13 逻辑复制深入
数据库深入🔥 1570
2
0 Postgresql存储、索引及系统优化、主备切换
PostgreSQL🔥 1495
3
一文读懂openguass dcf网络模块
集群🔥 1420
4
逻辑复制源码分析
数据库深入🔥 1327
5
PostgreSQL 分区表:从一行 `PARTITION BY` 到路由热路径的全链路拆解
数据库🔥 1094
6
applyparallelworker.c 之 LA 端源码深度解析:Leader Apply Worker 的指挥中枢
数据库深入🔥 1082
7
PostgreSQL Background Worker 全解:从 `RegisterBackgroundWorker` 到逻辑复制 4 类 worker 的全生命周期
数据库🔥 1078
8
PostgreSQL的后台进程walsender分析 - 关系型数据库 - 亿速云
PostgreSQL🔥 1033
9
PostgreSQL 逻辑复制的监控:六张视图 + 一组可执行 SQL,把 publisher/subscriber 的速率与健康度彻底看透
数据库🔥 1032
10
PostgreSQL 逻辑复制支持 DDL 之后:DDL 与 DML 的时序难题(重点:分区表)
数据库🔥 999
11
reorderbuffer.c 源码深度解析:PostgreSQL 逻辑复制的"事务重组引擎
数据库深入🔥 953
12
PostgreSQL 内核开发:读取一张表的 9 步标准流程与缓存全景
数据库🔥 938
13
从 `postgres` 二进制到生产级守护 —— PostgreSQL 最外层模块与启动全流程拆解
数据库🔥 936
14
支持逻辑复制同步 DDL 适配 SQL Server 方案
数据库深入🔥 934
15
PostgreSQL 逻辑复制的 ReorderBuffer 与事务机制:从一行 WAL 到一致性变更流的全链路绑定
数据库🔥 913
16
DDL同步架构(美化版)
数据库深入🔥 908
17
PostgreSQL Latch 机制详解:从一行 SetLatch 到 epoll 的内核之旅
数据库🔥 871
18
pgbench 源码全解:一个 C 文件如何撑起 PostgreSQL 官方压测工具
数据库🔥 860
19
PostgreSQL libpq 机制与缓冲区详解
数据库🔥 850
20
PostgreSQL 逻辑复制 spill 文件深度剖析:从 `xid-*.spill` 到 TPC-C 的增长方程
数据库🔥 845