我用 python 写了一个主动生成索引的脚本
简介:为了刷算法题,建了一个 GitHub仓库:PiperLiu / ACMOI_Journey,记录本人的刷题轨迹,并总结一下办法、心得。想到一个需要:能不能在我每新增一条题目的笔记后,利用程序主动地将其归类、创立索引?用 Python 实现一个入门级的小脚本,波及到文件读写、命令行参数、数组操作利用等知识点
,在此分享给敌人们。
需要实现
我有一个 Markdown 文档,长成上面这个样子:
# ACM/OI Journey在此留下刷题痕迹与刷题心得。不定期的方法论总结在这里[./notes/README.md](./notes/README.md)。学习材料:- OI Wiki: https://oi-wiki.org/- 力扣中国: https://leetcode-cn.com/## 归档## 日期归档
留神到,两个二级题目## 归档
与## 日期归档
下空洞无物。
我的需要是,我刷完一道题,就将其记录在## 日期归档
下,格局为: - uu 日期 题目名称与概括 类别A 类别B 类别C... [程序文件1] [程序文件2] [程序文件3]...
假如我明天刷了 2 道题,那么我就将其记录在我的## 日期归档
上面,如下所示。
## 日期归档- uu 2020.11.26 盛最多水的容器『因为两个边独特决定了下限,因而将较短边向内挪动,摈弃搜寻次优解』 双指针法 搜寻 [py](./vsc_leetcode/11.盛最多水的容器.py) [cpp](./vsc_leetcode/11.盛最多水的容器.cpp)- uu 2020.11.27 整数转罗马数字『生存中从大的位数开始形容数字,因而从大的数与字符开始匹配』 匹配 字符串 [cpp](./vsc_leetcode/12.整数转罗马数字.cpp)
而我的## 归档
上面还什么都没有,我心愿我的脚本能够主动帮我在## 归档
下创立三级目录:双指针法
、搜寻
、匹配
、字符串
,并且将对应的题目放到上面去。
最终的成果是:
## 归档- [匹配](#匹配)- [字符串](#字符串)- [双指针法](#双指针法)- [搜寻](#搜寻)### 匹配- 整数转罗马数字『生存中从大的位数开始形容数字,因而从大的数与字符开始匹配』 [cpp](./vsc_leetcode/12.整数转罗马数字.cpp) 2020.11.27### 字符串- 整数转罗马数字『生存中从大的位数开始形容数字,因而从大的数与字符开始匹配』 [cpp](./vsc_leetcode/12.整数转罗马数字.cpp) 2020.11.27### 双指针法- 盛最多水的容器『因为两个边独特决定了下限,因而将较短边向内挪动,摈弃搜寻次优解』 [py](./vsc_leetcode/11.盛最多水的容器.py) [cpp](./vsc_leetcode/11.盛最多水的容器.cpp) 2020.11.26### 搜寻- 盛最多水的容器『因为两个边独特决定了下限,因而将较短边向内挪动,摈弃搜寻次优解』 [py](./vsc_leetcode/11.盛最多水的容器.py) [cpp](./vsc_leetcode/11.盛最多水的容器.cpp) 2020.11.26## 日期归档- 2020.11.26 盛最多水的容器『因为两个边独特决定了下限,因而将较短边向内挪动,摈弃搜寻次优解』 双指针法 搜寻 [py](./vsc_leetcode/11.盛最多水的容器.py) [cpp](./vsc_leetcode/11.盛最多水的容器.cpp)- 2020.11.27 整数转罗马数字『生存中从大的位数开始形容数字,因而从大的数与字符开始匹配』 匹配 字符串 [cpp](./vsc_leetcode/12.整数转罗马数字.cpp)
通过 Markdown 引擎渲染后的成果如下图。
如上,我岂但新增了三级题目### 匹配
、### 字符串
等,还为三级题目创立了目录索引链接。
最终程序实现如下图。
Python 与脚本文件
这样就要派上咱们的 Python 出场了。我感觉这才是 Python 的老本行:脚本文件。记得Python猫已经有篇文章,讲过为什么 Python 中的正文符号是 #
而不是 //
。
起因很可能是:Python的老本行,就是写这一个个易用的脚本文件的,与shell
相似。
想想 Python 的特点:解释型语言、动静型语言、在命令行里能够一条一条地输出、os.system()
能够间接调用命令...所以,拿 Python 来执行一个个小工作(脚本文件)再适合不过了。
整体逻辑
逻辑是:
- 先把文件读到内存中,以列表
list
的模式保留 - 列表
list
内,每一元素对应一句话 - 遍历列表,遇到元素
## 归档
则其之后的元素依照不同条件取出、剖析 - 直到遇到元素
## 日期归档
,则把其之后的元素按条件取出、剖析
细节在代码里(代码文件refresh.py
),我应用汉语表明了。
""" """import os.path as ospimport redef refreah(): """ 我要解决的文件是 README.md 那么我获取其绝对路径 留神这里解决的文件和代码文件处于同一目录下 """ dirname = osp.dirname(__file__) filepath = osp.join(dirname, "README.md") """ 关上这个文件,其变量名是 f """ with open(filepath, 'r+', encoding='utf-8') as f: """ 将文件的内容读到内存 f.read() """ content = f.read() """ 以“换行符”/“回车”进行字符串宰割 这样,row_list 每个元素就是一行文字了 """ row_list = content.split('\n') """ 上面开始把不同的目录对应的条目取出 """ # found the un-packed row un_packed_rows = [] dict_cata = {} dict_row_flag = False date_row_flag = False dict_row_num = 0 date_row_num = 0 cur_cata = None for idx, row in enumerate(row_list): """ 如果到了 ## 归档 上面 """ if dict_row_flag: if "### " in row[:4]: cur_cata = row[4:] """ data_cata 是咱们的类别字典,最终成果为 data_cata = { "匹配": [匹配的第1题, 匹配的第2题, ...], "字符串": [字符串的第1题, 字符串的第2题, ...], ... } """ dict_cata.setdefault(cur_cata, []) elif "- " in row[:2] and not re.match('\[.*\]\(.*\)', row[2:]): """ 这里用了一个正则 因为索引格局为 - [索引名称](#索引名称) 而题目格局为 - 题目 程序 日期 因而如果仅凭是否以「- 」结尾,则难以辨别二者 因而加了一个是否正则匹配 [*](*) 的判断 """ dict_cata[cur_cata] = [row] + dict_cata[cur_cata] else: """ 判断是否到了 ## 归档 上面 """ if row == "## 归档": dict_row_flag = True dict_row_num = idx + 1 """ 如果到了 ## 日期归档 上面 """ if date_row_flag: """ - uu 是我本人设的格局 如果题目有 uu ,那么这条就是我要用脚本加到归档里的题目 """ if '- uu ' in row[:5]: un_packed_rows = [row] + un_packed_rows row_list[idx] = "- " + row[5:] else: """ 判断是否到了 ## 日期归档 上面 """ if row == "## 日期归档": date_row_flag = True dict_row_flag = False date_row_num = idx + 1 # pack those rows to "## 日期归档" """ 上面是把新题目(uu)加到 data_cata 字典中 """ for row in un_packed_rows: row = row.split(' ') file_num = 0 file_name = "" for ele in row: if re.match('\[.*\]\(.*\)', ele): file_num += 1 file_name += (ele + ' ') catas = row[4:-file_num] for c in catas: dict_cata.setdefault(c, []) row_ = '- ' + row[3] + ' ' + file_name + row[2] dict_cata[c].append(row_) # del file "## 归档" """ 上面是清空 ## 归档 的内容 依据 dict_cata 书写新的全部内容 """ row_list_a = row_list[:dict_row_num] row_list_c = row_list[date_row_num-2:] ## row_list_b row_list_b = [] for key in dict_cata: row_list_b.append("\n### " + key) for row in dict_cata[key]: row_list_b.append(row) row_list_b[0] = row_list_b[0][1:] row_list = row_list_a + row_list_b + row_list_c """ 把新解决好的文本,逐行写到文件中 (文件先清空,原文本被笼罩) """ with open(filepath, 'w', encoding='utf-8') as f: for row in row_list: f.write(row + '\n') """ 提醒用户,解决好了 """ print("\033[1;34mREADME.md refresh done\033[0m") print("\033[1;36mhttps://github.com/PiperLiu/ACMOI_Journey\033[0m") print("star" + "\033[1;36m the above repo \033[0m" + "and practise together!")def cata_index(): """ 这是我用于生成索引的函数 索引就是: ## 归档 - [匹配](#匹配) - [字符串](#字符串) - [双指针法](#双指针法) - [搜寻](#搜寻) 思路很简略,还是取各个三级题目 而后规整到 ## 归档 上面 """ dirname = osp.dirname(__file__) filepath = osp.join(dirname, "README.md") with open(filepath, 'r+', encoding='utf-8') as f: content = f.read() row_list = content.split('\n') cata_list = [] dict_row_flag = False dict_row_num = 0 cata_row_num = 0 for idx, row in enumerate(row_list): if dict_row_flag: if cata_row_num == 0: cata_row_num = idx if "### " in row[:4]: cata = row[4:] cata = "- [" + cata + "]" + "(#" + cata + ")" cata_list.append(cata) elif row == "## 归档": dict_row_flag = True dict_row_num = idx + 1 elif row == "## 日期归档": cata_list.append("\n") break # add idx row_list_a = row_list[:dict_row_num] row_list_c = row_list[cata_row_num:] row_list = row_list_a + cata_list + row_list_c with open(filepath, 'w', encoding='utf-8') as f: for row in row_list: f.write(row + '\n')refresh()cata_index()
最终的运行成果是,我在命令行执行该脚本,则文档主动规整。
argparse利用
留神到下面我输出了一个参数 -r
,这个是为了让 refresh.py
这个文件有更多功能,并且在不同参数时做不同的事。参数好像不同的「按钮」。
我将各个性能封装在不同函数中,将利用解耦,即不同性能间不相互依赖,防止出现逻辑谬误。
此外,我新建了一个函数,用于获取参数。
def get_args(): parser = argparse.ArgumentParser() parser.add_argument( '--refresh', '-r', action='store_true', help='refreah README.md' ) args = parser.parse_known_args()[0] return args
这样,咱们就能够获取到 -r
这个参数,在主过程里,咱们判断用户是否应用 r
这个性能,应用的话,则调用相应函数。
def main(args=get_args()): if args.refresh: refreah() cata_index()if __name__ == "__main__": main()
注意事项:encoding
此外,因为是中文,因而编码规定值得注意。
比方,在文件结尾退出 #-*- coding:UTF-8 -*-
;在 open 文件时,退出 encoding='uft-8'
参数。
值得改良的点:更好的正则
如果你读我的代码,你会发现读取、判断行的逻辑上有些“粗犷”。
仅仅通过判断 - []
等是否是行的前四个字符是不妥的,并且我在判断 - uu 日期 题目名称与概括 类别A 类别B 类别C... [程序文件1] [程序文件2] [程序文件3]...
时,也仅仅是通过 if else
判断是否有方括号、括号来辨别类别字段
与程序文件
字段。
这是不妥的,这样,我就难以在题目里自在书写。一个可行的改良,是应用弱小的正则表达式进阶属性。
尚无精力探讨,将来可能会进一步批改探讨,欢送继续关注我。
我的项目地址:https://github.com/PiperLiu/A...
欢送 star watch fork pr issue 五连。