批量生成pdf书签目录之目录自动格式化(Python实现)

2 篇文章 0 订阅
1 篇文章 0 订阅

一、动机

针对网上下载到的pdf书籍,很多都是没有书签目录的,给读者看起来很不方便,下面就有了这个半自动生成书签目录的方法。

本文的主要思路来源于Ghoset 博主的《批量给pdf添加目录(最完整详细方法)》,主要是把其中对目录手动格式化的一步进行了自动化,写成了代码,打包成了工具,算是一个补充。

二、利用正则将目录格式化简析

2.1 参考正则表达式模式

^匹配字符串的开头
$匹配字符串的末尾
a| b匹配a或b
(re)匹配括号内的表达式,也表示一个组
\s匹配任意空白字符,等价于 [\t\n\r\f].
\S匹配任意非空字符
\d匹配任意数字,等价于 [0-9].
\D匹配任意非数字
\1...\9匹配第n个分组的内容。

 2.2 目录正则替换简析

  2.2.1 待格式化目录(上)、格式化后目录(中)、格式效果实现(下)

格式化前:
"第一部分标 题	9"
" 第1章标题10"
"1.1标题	11"
"1.1.1标 题    12"

格式化后:
"第一部分 标 题    9"
"    第1章 标题    10"
"        1.1 标题    11"
"            1.1.1 标 题    12"

格式效果:
#1.一级目录实现:
# '第一部分'与'标题'之间一个空格;
# (行头匹配):匹配模式:^(第(\d|\D)+部分)' --> 替换模式:'\1 '
# 注:'\1'的使用需要匹配模式中用()分组,否则无效
#     '\1 '后有一个空格
#2.二级目录实现:
# '第1章'之前一个制表符'\t';'第1章'与'标题'之间一个空格;
# 首先得去除'第一章'前空格;
# 后(行头匹配):匹配模式:'^(第(\d|\D)+章)' --> 替换模式:'\t\1 '
#3.三级目录实现:
# '1.1'之前两个制表符'\t\t';'1.1'与'标题'之间一个空格;
# (行头匹配):匹配模式:'^(\d+\.\d+)' --> 替换模式:'\t\t\1 '
#4.四级目录实现:
# '1.1.1'之前三个制表符'\t\t\t';'1.1.1'与'标题'之间一个空格;
# (行头匹配):匹配模式:'^(\d+\.\d+\.\d+)' --> 替换模式:'\t\t\t\1 '
#5.页码实现:
# '标题'与页码'10'之间一个制表符'\t';
# (行尾匹配):匹配模式:'(\d+)$' --> 替换模式:'\t\1'

注:1.标题中的空格保留不动,不可随空格去除操作一起去除;

       2.标题中最后一个字符若为数字,会被程序当成是页码,这个暂时没有解决,需手动修改。

三、代码实现

3.1 代码目录结构

其中,主函数在“CatalogFormat.py”文件中;

    “catalog.txt”文件为存放的待格式化目录;

    “catalog_result.txt”文件为存放的格式化后的结果文件。

3.2 代码实现语言:Python2.7

   代码程序支持到三级目录,可包含章节之上的'部分'分类目录,用0|1区别

   若hasModule == 1 则将“第一部分 标题 9”作为一级目录;

   若hasModule == 0 则将“第一部分 标题 9”与“第一章 标题 10”同时作为一级目录

# -*- coding:UTF-8 -*-
# 此文件名:CatalogFormat.py
import re

#正则替换关联类
class Pattern_Replace_Link:
    regPattern = ''
    regReplace = ''
    def __init__(self, regPattern, regReplace):
        self.regPattern = regPattern
        self.regReplace = regReplace

#目录格式化Pdf
def CatalogFormat4Pdf(hasModule=0):
    # hasModule 表示是否包含‘第...部分’的目录层级,默认 0:不包含 | 1:包含

    #正则操作字典
    regex_opt_dicts = {
        # 将空白字符'\s',或者网络文本空白' ',转成单个空格' '
        'repSpace'   : Pattern_Replace_Link(r'(\s+| +)',        r' '),
        # 将可能存在的多个空格,转成单个空格' '
        'oneSpace'   : Pattern_Replace_Link(r'(  +)',            r' '),
        # 模块目录序号前顶格,后加一个空格' '
        'moduleSeq'  : Pattern_Replace_Link(r'^(第(\d|\D)+部分)',r'\1 '),
        # 一级目录序号前一个制表符'\t',后加一个空格' '
        'firstSeq'   : Pattern_Replace_Link(r'^(第(\d|\D)+章)',  r'\t\1 ' if(hasModule == 1) else r'\1 '),
        # 二级目录序号前两个制表符'\t',后加一个空格' '
        'secondSeq'  : Pattern_Replace_Link(r'^(\d+\.\d+)',      r'\t\t\1 ' if(hasModule == 1) else r'\t\1 '),
        # 三级目录序号前三个制表符'\t',后加一个空格' '
        'thirdSeq'   : Pattern_Replace_Link(r'^(\d+\.\d+\.\d+)', r'\t\t\t\1 ' if(hasModule == 1) else r'\t\t\1 '),
        # 页码前一个制表符'\t'
        'pageSeq'    : Pattern_Replace_Link(r'(\d+)$',           r'\t\1')
    }

    obj_file = open('catalog.txt', mode='r')
    result_file = open('catalog_result.txt', mode='w')

    for line in obj_file.readlines():

        # 将网络空白文本及普通空白'\s',替换为单个空格' '
        link = regex_opt_dicts['repSpace']
        line = re.sub(link.regPattern, link.regReplace, line)
        # 去除左右(前后)空格
        #注:strip()去除不了网络空格文本' '
        line = line.strip()

        # 模块中文目录匹配
        link = regex_opt_dicts['moduleSeq']
        line = re.sub(link.regPattern, link.regReplace, line)
        # 第一级中文目录匹配
        link = regex_opt_dicts['firstSeq']
        line = re.sub(link.regPattern, link.regReplace, line)

        # 二、三级数字目录匹配
        # 数字序号由最下层开始匹配
        # 如:1.2 和 1.2.1 中,先从头匹配 1.2.1
        # 因匹配是从头开始往后匹配的,所以匹配完一次,第二次将匹配不成功(开头多了'\t')
        link = regex_opt_dicts['thirdSeq']
        line = re.sub(link.regPattern, link.regReplace, line)
        link = regex_opt_dicts['secondSeq']
        line = re.sub(link.regPattern, link.regReplace, line)

        # 每层目录页号匹配
        link = regex_opt_dicts['pageSeq']
        line = re.sub(link.regPattern, link.regReplace, line)

        # 将可能存在的多个空格,转成单个空格' '
        link = regex_opt_dicts['oneSpace']
        line = re.sub(link.regPattern, link.regReplace, line)

        #追加换行符
        line += '\n'
        #写入结果文件
        result_file.write(line)

    #关闭文件
    obj_file.close()
    result_file.close()

# 函数入口
if __name__ == '__main__':

    print("*******************--******--*************************\n"\
          "*************--********--*******--********************\n"
          "Ensure the file catalog.txt under the current directory.")
    print("Then enter 0 or 1 to choose if it has Module (like \' " + unicode('章节之上还分 第一部分','utf-8') + "\')\n"\
          + "1:yes; 0:no\n")
    hasModule = input()
    while hasModule != 0 and hasModule != 1:
        print("Please enter 0 or 1:\n")
        hasModule = input()

    print("You choose " + str(hasModule) + "\n")

    print("Catalog Format Begin.....")
    CatalogFormat4Pdf(hasModule)
    print("Catalog Format Over.....")

四、生成CatalogFormat.exe可执行文件

参考博文 8. 如何把Python脚本导出为exe程序 

生成如下目录结构:(不需要Python环境,可在Windows下直接运行)

--CatalogFormat4PDF
----build
------CatalogFormat
--------Analysis-00.toc
--------CatalogFormat.exe.manifest
--------EXE-00.toc
--------PKG-00.pkg
--------PKG-00.toc
--------PYZ-00.pyz
--------PYZ-00.toc
--------warn-CatalogFormat.txt
--------xref-CatalogFormat.html
----dist
------catalog.txt          -->  待格式化目录
------catalog_result.txt   -->  目录格式化结果
------CatalogFormat.exe    -->  可执行程序(Windows下)
----CatalogFormat.spec

程序窗口:

首先需保证 CatalogFormat.exe同目录下的catalog.txt文件中已经放入了你的目录

(注:目录可从网上查找,最好是带页码的,如果没有只能手动添加)

    (目录可从“百科”、“当当”、“天猫”等书籍资料处搜索)

然后按控制台提示,如下操作:

 1.如果是这种目录结构,输入"1",回车:

"第一部分 标 题    9"
"    第1章 标题    10"
"        1.1 标题    11"
"            1.1.1 标 题    12"

  2.如果是这种目录结构,输入"0",回车:

"第1章 标题    10"
"    1.1 标题    11"
"       1.1.1 标 题    12"

格式化结果在catalog_result.txt文件中。 

可执行程序下载地址

链接:https://pan.baidu.com/s/14fFRL0siT7YMs1qAOTgBaw 
提取码:6ojk 

五、参考链接

1. 批量给pdf添加目录(最完整详细方法)

2. Python 正则表达式

3. Python 字典(Dictionary)

4. Python File(文件) 方法

5. Python 面向对象

6. python中字符串连接的四种方式

7. 【Python系列】Python3获取控制台输入

8. 如何把Python脚本导出为exe程序

9. Python打包为exe使用py2exe时中文乱码问题

评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值