工具分享:清理 Markdown 中没有引用的图片
前言:
之前,我写笔记的工具一直都是notion,而且没有写博客的习惯。但是一是由于notion的服务器在国外,有时候很不稳定;二是由于notion的分享很不方便,把笔记分享给别人点开链接之后还要先登录才能查看内容。于是我又在 掘金 平台写了几篇随笔,但是掘金的文章无法通过本地 Markdown 上传直接发表,也无法下载之前上传过的文章,这样一来数据不保存在本地,以后迁移文章到别的平台的成本也更高。
后来在 Bilibili up主 TheCW 的推荐下学会使用了 Linux 和 vim,然后就喜欢上了使用vim写 Markdown 这种双手不需要离开键盘的感觉。而且博客园也开放了Metaweblog接口,可以很方便的将本地的笔记发表到自己的博客园。
灵感来源
使用 vim 写笔记不像 notion 一样,可以随时将不需要的图片删除而不会在本地留下垃圾文件,(typora 没怎么用过,不知道有没有类似的功能)而删除了本地笔记的图片引用之后还是会在文件夹留下垃圾图片残留,之前的做法是每次删除完图片都在文件夹里寻找名字相同的图片之后删除,这种方法低效费时,于是便萌生了写一个自动清理无引用图片小工具的想法。
Python
本着不重复造轮子的原则,我先在国内互联网搜寻了一番(看不懂英语),只看到 CSDN 上有人用 java 写了一个类似的工具,但是内容不太看得懂,而且没有提供现成的工具包下载,只有源码。(本人比较懒...)
这种小工具当然还是用 Python 更友好啦~ 而且我是为了写这么一个东西才从头看的 Python,可以说之前对这门语言一无所知,只知道很火...... 小工具只有一个 .py 文件:
# utf-8
如何使用
因为只有一个文件,所以大家花一分钟看下源码大概就知道了,原理极其简单。(一个学了一下午 python 的人能写出什么复杂的东西)
将
.py文件 拷贝/移动到自己喜欢的位置,将该路径设置为 环境变量 路径,或者使用软链接到/usr/bin目录下因为能力有限且开发时间较短,工作目录必须严格遵循以下形式(未来可能会优化)
.
├── imgs
│ ├── a.jpg
│ ├── b.png
│ └── c.png
├── list.md
├── note.md
└── time.md

这里的意思是说:所有的 Markdown 文件需要位于当前目录下,而所有的图片文件需要位于
./imgs路径下 (图片文件夹的名字可以是任意,不是必须叫imgs)
- 移动到你想要清理无引用图片的上级目录(该目录下应该有
a.mdb.md......imgs/)
例如我这里有一个从 Notion 上下载下来的 Vue 笔记,但是我不小心在里面加了许多其他没用的图片,现在想删掉这些图片

该目录下只有一个 Vue-notion.md 和一个放有图片的文件夹 vuedir
- 使用
python $APP_HOME/img-cleaner.py
# 原谅我这种愚蠢的写法
- 这里会提示需要你输入放置图片文件夹的名称:

输入之后按回车


没有引用过的图片就会被移动到 ./_trash_bin 目录下
注意点
每行最多包含一个图片标签
![](),因为没有关闭正则的贪婪匹配,如果多个图片写在一行的话则会报错2022-6-2 更新:所引用图片的文件名可以带 空格符 ,代码会自动将 Markdown 内引用路径的文件名中的%20转码为 空格符,不过只允许在文件名中出现一次 空格符
源码
# -*-coding:utf-8 -*-
import re
import shutil
import os
# 获取工作路径
print("请输入你放置图片文件夹的名称: ")
print("注意,如果路径含有特殊符号需要用「\」转义")
_input = input()
# 创建 replace _trash_bin文件夹
if os.path.exists('./replace') == False:
os.mkdir('./replace')
print("创建文件夹成功:replace")
else:
raise Exception("请删除当前目录下的 replace 文件夹后重试")
if os.path.exists('./_trash_bin') == False:
os.mkdir('./_trash_bin')
print("创建文件夹成功:_trash_bin")
else:
raise Exception("请删除当前目录下的 _trash_bin 文件夹后重试")
# 撰写正则表达式
# pattern = re.compile('\(.*img\/.*\..*\)')
# pattern = re.compile('\(' + _input + '\/.*\..*\)')
pattern = re.compile('\!\[.*\]\(' + _input + '\/.*\)')
# 创建需要被移动的文件列表
find_list = []
# 获取当前路径下的 .md 文件
md_finder = os.listdir('./')
md_list = []
for item in md_finder:
# 寻找 markdown 文件
if item.endswith('.md') == True:
md_list.append(item)
# 逐个读取 .md 文件
for md_item in md_list:
f = open(md_item)
md_str = f.read()
f.close()
result = pattern.findall(md_str)
for i in range(len(result)):
# 将图片路径逐个添加至 find_list
index = result[i].find("]")
# 将拿到的原始图片路径加工成 ./<imgs_name>/xxx.png 的形式
add_item = "./" + _input + "/" + result[i][index + 3 + len(_input): len(result[i]) - 1]
space_index = add_item.find("%20")
# 如果路径中存在 空格符
if space_index != -1:
add_item = add_item[0: space_index] + " " + add_item[space_index + 3:]
# 将图片路径添加至 find_list
find_list.append(add_item)
# 将所有 markdown中 引用过路径的图片移动至 ./replace
for item in find_list:
shutil.move(item, './replace')
print(item + " 移动完成")
print("----------------------")
# 将没有引用的图片移至 _trash_bin
img_trashs = os.listdir('./' + _input)
trash_flag = 0
for item_trash in img_trashs:
item_trash = "./" + _input + "/" + item_trash
trash_flag = trash_flag + 1
shutil.move(item_trash, './_trash_bin')
print(item_trash + " in _trash_bin")
print("----------------------")
# 删除原本的 img 文件夹,并更改文件夹名称
os.removedirs('./' + _input + '/')
os.rename('./replace', _input)
print(str(trash_flag) + " 个 未引用")
print("移动成功!没有引用的图片已经移入至 _trash_bin")
工具分享:清理 Markdown 中没有引用的图片的更多相关文章
- 如何在webpack中成功引用到图片?
打包图片时,你可曾遇到在产出目录文件夹找不到图片,即便找到了,但是页面说引用不到资源?页面上或者文件中引用的图片地址不对? 一.在webpack中引入图片需要url-loader //webpack配 ...
- markdown中设置、调整图片尺寸
使用百分比描述尺寸 <img src="https://img2018.cnblogs.com/blog/1122471/201902/1122471-2019022218575673 ...
- DB数据导出工具分享
一个根据数据库链接字符串,sql语句 即可将结果集导出到Excel的工具 分享,支持sqlserver,mysql. 前因 一个月前朋友找到我,让我帮忙做一个根据sql导出查询结果到Excel的工具( ...
- 将 R 整合到 markdown 中
markdown 易于写入和读取,具有编写报告的必要功能,例如简单的文本格式,嵌入图片.链接.表.引用.数学公式以及代码块.虽然在 markdown 中编写纯文本很容易,但是创建具有许多图片和表格的报 ...
- 一键清理 Nexus 中无用的 Docker 镜像
现许多团队使用 Nexus 来管理 Docker 镜像,产品不断迭代,镜像仓库占用的磁盘空间也越来越大.由于 Nexus 的控制台并未提供批量操作镜像功能,清理镜像十分不便.本文分享一个清理 Nexu ...
- 浅谈Java中的引用
在Java语言中,引用是指,某一个数据,代表的是另外一块内存的的起始地址,那么我们就称这个数据为引用. 在JVM中,GC回收的大致准则,是认定如果不能从根节点,根据引用的不断传递,最终指向到一块内存区 ...
- Markdown中插入数学公式的方法
Markdown中插入数学公式的方法 文章来源:http://blog.csdn.net/xiahouzuoxin/article/details/26478179 自从使用Markdown以来,就开 ...
- c++中的引用与指针的区别
http://blog.csdn.net/lyd_253261362/article/details/4323691 c++中的引用与指针的区别 ★ 相同点: 1. 都是地址的概念: 指针指向一块内存 ...
- Unity协程(Coroutine)管理类——TaskManager工具分享
博客分类: Unity3D插件学习,工具分享 源码分析 Unity协程(Coroutine)管理类——TaskManager工具分享 By D.S.Qiu 尊重他人的劳动,支持原创,转载请注明出处 ...
随机推荐
- Java 将Map按Value值降序排列
1 /** 2 * 将集合按照降序排列-FLOAT 3 * @param nowPartTwoData 4 * @return 5 */ 6 private static List<Map.En ...
- Blazor组件自做九: 用20行代码实现文件上传,浏览目录功能 (3)
接上篇 Blazor组件自做九: 用20行代码实现文件上传,浏览目录功能 (2) 7. 使用配置文件指定监听地址 打开 appsettings.json 文件,加入一行 "UseUrls&q ...
- Unable to negotiate with xx.xxx.xxxx port 22: no matching host key type found. Their offer: ssh-rsa(解决的两种方式)
异常问题: 下班之前升级了一下Git的版本,结果第二天过来拉取远程最新代码的时候就提示了下面的异常问题: Unable to negotiate with xx.xxx.xxxx port 22: n ...
- 基于.NetCore开发博客项目 StarBlog - (1) 为什么需要自己写一个博客?
前言 OK,我也来造轮子了 博客系统从一开始用WordPress,再到后来用hexo.hugo之类的静态博客生成放github托管,一直在折腾 折腾是为了更好解决问题,最终还是打算自己花时间搞一个好了 ...
- instanceof 和类型转换
instanceof 和类型转换 instanceof 判断a 和 B 类型是否相似 公式 System.out.println(a instanceof B); //true / false 编译是 ...
- 4.Java开发环境的搭建
Java开发环境搭建 一.JDK下载与安装 JDK8下载地址 选择目录,点击下一步 二.配置环境变量 变量名:JAVA_HOME 变量值:JDK安装路径 变量值:CLASSPATH 变量值:.;%JA ...
- 安卓记账本开发学习day2
今天遇到了xml文件报错,Wrong orientation? No orientation specified, and the default is horizontal, yet this la ...
- 算法基础③--DFS解决迷宫问题入门
迷宫问题 通过深度优先搜索(DFS)方法实现. 迷宫问题一 一天蒜头君掉进了一个迷宫里面,蒜头君想逃出去,可怜的蒜头君连迷宫是否有能逃出去的路都不知道. 看在蒜头君这么可怜的份上,就请聪明的你告诉蒜头 ...
- thinkphp6事件监听event-listene
事件系统可以看成是行为系统的升级版,相比行为系统强大的地方在于事件本身可以是一个类,并且可以更好的支持事件订阅者. 事件相比较中间件的优势是事件比中间件更加精准定位(或者说粒度更细),并且更适合一些业 ...
- python基础练习题(题目 递归输出)
day19 --------------------------------------------------------------- 实例027:递归输出 题目 利用递归函数调用方式,将所输入的 ...