利用 Python 脚本批量创建空白 Markdown 笔记
文章目录
- 利用 Python 脚本批量创建空白 Markdown 笔记
- 1 背景介绍
- 2 需求描述
- 3 明确思路
- 4 具体实现
- 4.1. 遍历 toc.md 文件,收集文件名和对应的文件内容
- 4.2. 实现文件批量生成逻辑
- 4.3. 补全缺失的工具函数
- 4.4. 进一步补全工具函数中的工具函数
- 5 脚本运行
- 6 注意事项
利用 Python 脚本批量创建空白 Markdown 笔记
1 背景介绍
我学视频课有个习惯:每学完一节课,就相应创建一个 Markdown 格式的纯文本自学笔记,方便日后查阅。久而久之,要创建的笔记文件越来越多,如果再要求这些文件都具备统一的格式(例如文件名的命名风格、统一的标题模板等等),无形中就会多出不少工作量。之前我都是用 PowerShell + ChatGPT 来批量生成这些文件夹和文件名,虽然脚本编写比较繁琐,但可以一劳永逸,倒也划算;前段时间入坑 Python,正好可以练练文件操作和正则表达式,才发现 Python 处理起这类问题来比 PowerShell 轻松太多了。
2 需求描述
这里随便找了一个视频课,原始的课程目录长这样:

【图 1:原始课程目录结构(节选)】
复制到一个临时文件 toc.md 后长这样:

【图 2:复制到临时文件 toc.md 后的课程目录(节选)】
而我想要的效果,是用 Python 脚本批量生成这样的文件结构:

【图 3:最终希望实现的笔记目录结构与内容模板】
3 明确思路
再复杂的需求也可以拆分成若干个可以轻松实现的单元。多行的批量处理可以先简化为某一行的处理:
- 读取
toc.md的某一行,赋给一个变量line; - 判定
line是按文件夹处理,还是按.md文件处理(通过正则表达式判定);- 是文件夹:
- 创建该文件夹;
- 提取章节编号(如
Ch01),以便本章笔记文件使用; - 重置笔记文件的二级目录编号(比如上一行编号为
Ch01.2,这一行需要重置为Ch2.1)
- 是文件:
- 获取当前章节编号,生成对应的文件名
- 获取当前章节编号,生成对应的
Markdown文本内容 - 二级目录编号递增
1
- 是文件夹:
- 遍历完
toc.md后,根据文件名是否以.md结尾,可以判定生成的是文件夹还是Markdown文件:- 是文件夹:创建该文件夹,并更新当前路径(
curr_path,以便后续笔记文件引用); - 是文件:根据当前路径生成对应的笔记文件,同时写入文本内容。
- 是文件夹:创建该文件夹,并更新当前路径(
4 具体实现
4.1. 遍历 toc.md 文件,收集文件名和对应的文件内容
创建 Python 脚本文件 generate_files.py,确定信息采集逻辑:
def make_chapter(line):pass
def make_section(line, chp_num, sec_num):pass# 参数初始化
chp_num = '0' # 章节号
sec_num = 1 # 小节号
(contents, file_names) = ([], []) # 初始化章节内容、文件名# 读取课程目录文件
with open('./toc.md', 'r') as f:# 读取文件的每一行,去掉行尾的换行符,然后存入列表 lineslines = [l.strip() for l in f.readlines()] for line in lines:# 判断行首是否是数字,如果是,说明是章节标题starts_with_digit = re.match(r'^(\d+)\.', line)if starts_with_digit:# 如果是章节标题,则生成该章节的 文件名 和 章节号(file_name, chapter_num) = make_chapter(line)# 添加本章的章节内容(仅占位用,文件夹没有文本内容)contents.append('placeholder')# 添加本章的文件名file_names.append(file_name)# 更新章节号chp_num = chapter_numelse:# 如果不是章节标题,则生成该小节的 文本内容 和 文件名(sec_file_name, sec_content) = make_section(line, chp_num, sec_num)# 添加该小节的文本内容file_names.append(sec_file_name)# 添加该小节的文件名contents.append(sec_content)# 按本行的实际作用动态更新小节编号sec_num = 1 if starts_with_digit else (sec_num + 1)
注意:make_chapter 函数(L1、L22)和 make_section 函数(L3、L34)暂不实现,先确定大流程。
4.2. 实现文件批量生成逻辑
利用 4.1 的信息采集逻辑,就可以批量生成文件/文件夹了:
# 批量生成文件
curr_path = ''
for index, (file_or_path, cont) in enumerate(zip(file_names, contents)):if file_or_path.endswith('.md'):file = file_or_pathwith open(f'./{curr_path}/{file}', 'w') as f:f.write(cont + '\n')else:path = file_or_pathos.makedirs(path, exist_ok=True)curr_path = path
4.3. 补全缺失的工具函数
大流程确定后,再来实现 make_chapter 函数和 make_section 函数:
#!/usr/bin/env pythonimport re
import osdef dashed(s, sep=' '):passdef sanitize_filename(s):passdef repl(match):passdef make_chapter(line):"""Generates the specific file name and the corresponding chapter number for this chapter.Args:line (string): The original line of text to be processed.Returns:tuple: A tuple containing the file name and the chapter number.Example:Input: line: '1. Getting Started with GitHub Actions'Output: ('Ch01_Getting_Started_with_GitHub_Actions.md', '1')"""pttn = r'(\d+)\.(.*)'re.findall(pttn, line)file_name = re.sub(pttn, repl, line)chapter_num = re.sub(pttn, r'\1', line) return (file_name, chapter_num)def make_section(line, chapter_num, section_num):"""Generates the specific file name and corresponding content for this section.Args:line (string): The original line of text to be processed.chapter_num (string): The current chapter number.section_num (int): The current section number.Returns:tuple: A tuple containing the file name and the content of the section.Example:Input: line: ' - Welcome to the Course!'chapter_num: '1'section_num: 1Output: ('Ch01_1_Introduction_to_the_Course.md', '## Ch01.1 Introduction to the Course')"""line = line.strip('- ')header_part = f'Ch{chapter_num.zfill(2)}_{section_num}'content_part = dashed(line, '_').replace('---', '_')file_name = f'{header_part}_{content_part}'title_content = f'## Ch{chapter_num.zfill(2)}.{section_num} {line}'return (f'{sanitize_filename(file_name)}.md', title_content)
4.4. 进一步补全工具函数中的工具函数
为了方便管理,再对工具函数中出现的几个工具函数做进一步实现:
def dashed(s, sep=' '):"""Removes leading and trailing whitespaces and replaces all other whitespaces with the specified separator.Args:s (str): The original string to be processedsep (str, optional): The separator string. Defaults to ' '.Returns:string: The processed string."""return sep.join(s.strip().split())def sanitize_filename(s):"""Sanitizes the file name by removing all characters except letters, numbers, underscores, and dots.Args:s (string): The original file name to be sanitized.Returns:string: The sanitized file name."""# 只保留字母、数字、下划线和点,其他字符都删除pttn = r'[^\w -]'re.findall(pttn, s)return re.sub(pttn, '', s)def repl(match):"""Generates the specific file name for this chapter.Args:match (Match[string]): The matched object from the regular expression.Returns:string: The file name for this chapter."""num = match.group(1)content = match.group(2)file_name = f'Ch{num.zfill(2)}_{dashed(content, "_")}'return sanitize_filename(file_name)
5 脚本运行
使用以下命令运行脚本:
python generate_files.py
不到两秒,就生成了所有的文件夹和 Markdown 空白文件:

【图 4:检查最终的批量生成结果(符合预期)】
6 注意事项
由于是第一次尝试 Python 脚本,调试过程中走了不少弯路,这里集中梳理一下:
- 一定要小步走,多迭代;
- 按抽象层次依次实现每一层的函数逻辑,方便后续管理;
- 读取每一行文本都会包含一个
\n换行符,需要用str.strip()处理掉; - 先用
re.findall捕获匹配结果,然后再用re.sub执行替换,否则后者始终输出空字符串; - 访问捕获的结果时,注意
f-string和r-string中反斜杠\的不同写法,前者要写成\\,而后者直接写成\即可; - 脚本运行前提前做好备份(以避免
rm -Recurse -Force *把Python脚本文件本身也删没了的杯具。。); - 尽量避免引用全局变量,多用参数传参(本例必须使用全局变量,以实时获取当前的文件夹名称和路径);
- 主体框架确定后,今后只需要修改文件夹和文件的处理逻辑,就可以适应不同的原始数据。
os.makedirs(path, exist_ok=True)中的exist_ok参数用于控制在指定路径已经存在时的行为:- 当
exist_ok=True时,如果目标目录已经存在,makedirs不会抛出异常(本例暂不涉及); - 当
exist_ok=False(默认值)时,如果目标目录已存在,则会抛出FileExistsError异常。 - 重视代码注释和函数文档(docstring)的书写,既方便别人,也方便自己(主要是写给自己看的)
相关文章:
利用 Python 脚本批量创建空白 Markdown 笔记
文章目录 利用 Python 脚本批量创建空白 Markdown 笔记1 背景介绍2 需求描述3 明确思路4 具体实现4.1. 遍历 toc.md 文件,收集文件名和对应的文件内容4.2. 实现文件批量生成逻辑4.3. 补全缺失的工具函数4.4. 进一步补全工具函数中的工具函数 5 脚本运行6 注意事项 利…...
【Qt】C++11 Lambda表达式
1. 举例 connect(ui->pushButton, &QPushButton::clicked, [](bool checked){//具体代码qDebug() << "Hello" << checked;}); 2. 详情 //完整形式 [ capture ] ( params ) opt -> ret { body; }; capture 是捕获列表params 是参数表opt 是函数…...
怎样提高服务器中的数据传输速度?
服务器中的数据传输速度会影响着用户的体验感,当企业中的数据传输速度出现卡顿或者是过慢时,用户不能及时浏览到所需的内容,给用户造成不好的体验感,那么企业该怎样才能提高服务器中的数据传输速度呢? 服务器之间如何传…...
Vue 封装公告滚动
文章目录 需求分析1. 创建公告组件Notice.vue2. 注册全局组件3. 使用 需求 系统中需要有一个公告展示,且这个公告位于页面上方,每个页面都要看到 分析 1. 创建公告组件Notice.vue 第一种 在你的项目的合适组件目录下(比如components目录&a…...
JVM实战—12.OOM的定位和解决
大纲 1.如何对系统的OOM异常进行监控和报警 2.如何在JVM内存溢出时自动dump内存快照 3.Metaspace区域内存溢出时应如何解决(OutOfMemoryError: Metaspace) 4.JVM栈内存溢出时应如何解决(StackOverflowError) 5.JVM堆内存溢出时应该如何解决(OutOfMemoryError: Java heap s…...
【python翻译软件V1.0】
如果不想使用密钥的形式,且需要一个直接可用的中英文翻译功能,可以使用一些免费的公共 API,如 opencc 或其他无需密钥的库,或直接用 requests 获取翻译结果。 其中,我可以给你一个简单的代码示例,使用 tra…...
Spring Boot中的依赖注入是如何工作
Spring Boot 中的依赖注入(Dependency Injection,简称 DI)是通过 Spring 框架的核心机制——控制反转(Inversion of Control,IOC)容器来实现的。Spring Boot 基于 Spring Framework,在应用中自动…...
ubuntu22.04 编译安装libvirt 10.x
环境安装 sudo apt-get update -y sudo apt-get install qemu-system-x86 bridge-utils libyajl-dev -y sudo apt-get install build-essential autoconf automake libtool -y sudo apt-get install libxml2-dev libxslt1-dev libgnutls28-dev libpciaccess-dev libnl-3-de…...
[fastadmin] 第三十四篇 FastAdmin 商城模块标签使用详解
FastAdmin 商城模块标签使用详解 一、标签基本语法 1.1 基础语法格式 {shop:goodslist flag"参数值" id"变量名" row"数量"}<!-- 循环内容 --> {/shop:goodslist}1.2 常用参数说明 flag: 商品标记筛选id: 循环变量名row: 显示数量 1.…...
(2024,LLaVA-Bench (Wilder),LLaVA-NeXT,LLaMA3,Qwen-1.5,语言模型扩展)
LLaVA-NeXT: Stronger LLMs Supercharge Multimodal Capabilities in the Wild 目录 1. 简介 2. 探索大规模语言模型的能力极限 3. LLaVA-Bench (Wilder):日常生活视觉聊天基准 4. Benchmark 结果 1. 简介 我们通过引入近期更强大的开源大语言模型(…...
IPEX-LLM开发项目过程中的技术总结和心得
IPEX-LLM开发项目过程中的技术总结和心得 在人工智能快速发展的时代,高效地开发和部署大语言模型(LLM)已成为技术人员的必备技能。在我们的项目中,我们采用了 Intel Extension for PyTorch(简称 IPEX)和 L…...
HTTP/HTTPS ②-Cookie || Session || HTTP报头
这里是Themberfue 上篇文章介绍了HTTP报头的首行信息 本篇我们将更进一步讲解HTTP报头键值对的含义~~~ ❤️❤️❤️❤️ 报头Header ✨再上一篇的学习中,我们了解了HTTP的报头主要是通过键值对的结构存储和表达信息的;我们已经了解了首行的HTTP方法和UR…...
【软考】软件设计师
「学习路线」(推荐该顺序学习,按照先易后难排序) 1、上午题—计算机系统(5~6分)[1.8; ] 2、上午题—程序设计语言(固定6分)[1.9; ] 3、下午题—试题一(15分) 4、上午题—…...
K8s Pod OOMKilled,监控却显示内存资源并未打满
1. 问题现象 pod一直重启,通过grafana查看,发现内存使用率并没有100%。 2. 排查过程 2.1 describe查看pod最新一次的状态 可以明显看到,最近一次的重启就是因为内存不足导致的。 2.2 describe 查看node节点状态 找到原因了,原来…...
C++ 原子变量
C 原子变量 文章目录 C 原子变量1. 原子变量是什么?2. 原子操作的特点3. 原子变量的作用1. 多线程安全的共享数据访问2. 替代锁机制3. 实现低级同步算法 4. 原子变量的常见操作5. 内存顺序(Memory Ordering)内存顺序控制在原子变量中的作用如…...
linux网络 | http结尾、理解长连接短链接与cookie
前言:本节是http章节的最后一部分,主要解释一些小概念。讲解到了HTTP的方法,表单, 重定向等等。 现在废话不多说, 开始我们的学习吧。 ps:本节内容都是概念, 知道就行, 友友们放心观…...
金融项目实战 02|接口测试分析、设计以及实现
目录 ⼀、接口相关理论 二、接口测试 1、待测接口:投资业务 2、接口测试流程 3、设计用例理论 1️⃣设计方法 2️⃣工具 4、测试点提取 5、测试用例 ⼀、接口相关理论 1、ui功能测试和接⼝测试那个先执⾏?为什么? 结论:…...
二、智能体强化学习——深度强化学习核心算法
2.1 DQN 系列及其改进 2.1.1 背景与动机 在经典强化学习中(如 Q-Learning),如果状态空间或动作空间非常大乃至连续,那么用一个表格来存储 Q ( s , a ) Q(s,a) Q(s,a) 不再可行。为了解决该问题,可以使用神经网络来逼…...
Mysql--架构篇--存储引擎InnoDB(内存结构,磁盘结构,存储结构,日志管理,锁机制,事务并发控制等)
MySQL是一个多存储引擎的数据库管理系统,支持多种不同的存储引擎。每种存储引擎都有其独特的特性、优势和适用场景。选择合适的存储引擎对于优化数据库性能、确保数据完整性和满足业务需求至关重要。 注:在同一个Mysql的数据库中,对于不同的表…...
JVM实战—13.OOM的生产案例
大纲 1.每秒仅上百请求的系统为何会OOM(RPC超时时间设置过长导致QPS翻几倍) 2.Jetty服务器的NIO机制如何导致堆外内存溢出(S区太小 禁NIO的显式GC) 3.一次微服务架构下的RPC调用引发的OOM故障排查实践(MAT案例) 4.一次没有WHERE条件的SQL语句引发的OOM问题排查实践(使用MA…...
抖音增长新引擎:品融电商,一站式全案代运营领跑者
抖音增长新引擎:品融电商,一站式全案代运营领跑者 在抖音这个日活超7亿的流量汪洋中,品牌如何破浪前行?自建团队成本高、效果难控;碎片化运营又难成合力——这正是许多企业面临的增长困局。品融电商以「抖音全案代运营…...
Golang dig框架与GraphQL的完美结合
将 Go 的 Dig 依赖注入框架与 GraphQL 结合使用,可以显著提升应用程序的可维护性、可测试性以及灵活性。 Dig 是一个强大的依赖注入容器,能够帮助开发者更好地管理复杂的依赖关系,而 GraphQL 则是一种用于 API 的查询语言,能够提…...
家政维修平台实战20:权限设计
目录 1 获取工人信息2 搭建工人入口3 权限判断总结 目前我们已经搭建好了基础的用户体系,主要是分成几个表,用户表我们是记录用户的基础信息,包括手机、昵称、头像。而工人和员工各有各的表。那么就有一个问题,不同的角色…...
【快手拥抱开源】通过快手团队开源的 KwaiCoder-AutoThink-preview 解锁大语言模型的潜力
引言: 在人工智能快速发展的浪潮中,快手Kwaipilot团队推出的 KwaiCoder-AutoThink-preview 具有里程碑意义——这是首个公开的AutoThink大语言模型(LLM)。该模型代表着该领域的重大突破,通过独特方式融合思考与非思考…...
1.3 VSCode安装与环境配置
进入网址Visual Studio Code - Code Editing. Redefined下载.deb文件,然后打开终端,进入下载文件夹,键入命令 sudo dpkg -i code_1.100.3-1748872405_amd64.deb 在终端键入命令code即启动vscode 需要安装插件列表 1.Chinese简化 2.ros …...
Springcloud:Eureka 高可用集群搭建实战(服务注册与发现的底层原理与避坑指南)
引言:为什么 Eureka 依然是存量系统的核心? 尽管 Nacos 等新注册中心崛起,但金融、电力等保守行业仍有大量系统运行在 Eureka 上。理解其高可用设计与自我保护机制,是保障分布式系统稳定的必修课。本文将手把手带你搭建生产级 Eur…...
Reasoning over Uncertain Text by Generative Large Language Models
https://ojs.aaai.org/index.php/AAAI/article/view/34674/36829https://ojs.aaai.org/index.php/AAAI/article/view/34674/36829 1. 概述 文本中的不确定性在许多语境中传达,从日常对话到特定领域的文档(例如医学文档)(Heritage 2013;Landmark、Gulbrandsen 和 Svenevei…...
HDFS分布式存储 zookeeper
hadoop介绍 狭义上hadoop是指apache的一款开源软件 用java语言实现开源框架,允许使用简单的变成模型跨计算机对大型集群进行分布式处理(1.海量的数据存储 2.海量数据的计算)Hadoop核心组件 hdfs(分布式文件存储系统)&a…...
GruntJS-前端自动化任务运行器从入门到实战
Grunt 完全指南:从入门到实战 一、Grunt 是什么? Grunt是一个基于 Node.js 的前端自动化任务运行器,主要用于自动化执行项目开发中重复性高的任务,例如文件压缩、代码编译、语法检查、单元测试、文件合并等。通过配置简洁的任务…...
Windows安装Miniconda
一、下载 https://www.anaconda.com/download/success 二、安装 三、配置镜像源 Anaconda/Miniconda pip 配置清华镜像源_anaconda配置清华源-CSDN博客 四、常用操作命令 Anaconda/Miniconda 基本操作命令_miniconda创建环境命令-CSDN博客...
