如何用正则表达式批量替换md文件中的frontmatter?

背景

  • 我在win上用Obsidian,Obsdian以前的多行标签的写法是"- #Done"
  • 我需要用Obsidian的插件make.md中的Smart Sapce功能,但是make.md并不识别标签格式"- #Done",只识别- Done

我的解决思路

  1. 等make.md支持该格式。(但是这个很无语,明明OB它自己能支持,dataview插件也能支持)
  2. 找方法批量修改,也就是用正则表达式,将"- #Done"变成- Done

求方法

根据以下帖子,我用dnGrep来正则替换,并不成功(搜索都搜索不到),请问是哪里有问题?
我已经尝试过新建.txt文件,可以搜索出来。
也尝试过将.md文件,删除只剩下匹配项,搜索不出来。难道是不支持.md文件吗?


没找到合适的样本,感觉这个替换用文本也行啊。

或者去项目页面提一下看开发者能不能改进。

多个文本文件替换,我习惯用vscode直接打开文本所在目录后,选择全局替换

"- #Done" 变成- Done直接选择大小写、全字匹配就行吧?

替换前记得先备份或者先替换单个文件看看效果

1 个赞

标签有上百个了,所以才需要用正则表达式。

我有上百个标签,上百个md文件,所以只能是正则表达式

可以用 busybox-w32,写一个 unix shell 脚本,配合 sed 进行替换。

首先安装 busybox-w32,可以参考我之前的一个帖子:

脚本可以这么写:

#!/bin/sh

for FILE in *.md
do
    sed -i 's/"- #Done"/- Done/g' $FILE
done

将上述代码保存为 test.sh,放在存放 md 文档的文件夹中。

然后,到存放 md 文档的文件夹中,命令行下执行:

busybox ash test.sh

解释一下代码中的内容:sed 的基本语法是

sed -i 's/待匹配的正则表达式/替换目标/g' 要处理的文件

它可以将文件中的 待匹配正则表达式 替换为 替换目标 字符串。

参考资料:

1 个赞

你上百个文件都是只需要将"- #Done" 变成- Done

你提供几个文件的文本内容看下,全字匹配和替换数量没关系的,正则的话要看了文本内容才能写

非也,好多不同的标签

如下,因为每个笔记是通过模版生成的,所以结构是差不多的

---
Created-time: <% tp.date.now() %>
tags:
  - "#Undo"
aliases: 
Link: 
Summary: 
Remark: 
---

意思是去掉标签名前的#吗?

替换前:

替换后:

这样的效果?

用dnGrep实操了一下,原样复刻你的操作,可以实现替换修改obstain 的 md文件

你写的正则表达式不能匹配这种
匹配的目标是

 "- #Undo"

注意引号的位置。。。

感谢指正。应该是这个问题,明天再试一理

如果严谨的话,这个问题大概不容易一步到位。

楼主问题不完善,我先想当然补充一下:

  • 要确认内容在 Front Matter 之中;
  • 要确认在 tags 字段之中;
  • 多个标签,大概如下:
---
Created-time: <% tp.date.now() %>
tags:
  - "#Undo"
  - "#otherTag"
aliases: 
Link: 
Summary: 
Remark: 
---

这种最好用脚本去控制逐步缩小范围替换,这样不容易出错,程序也容易写。

现在假定无需验证处于 Front Matter 之中,或者说可以确保正文没有类似内容,那么可以尝试用正则 (?<=^tags:\n) - "#(.*?)" 去匹配第一个标签,解释如下:

  • 第一个括号是零宽正向后行断言(zero-width positive lookbehind assertion),就是说查找的结果前面必须有什么;
    • 必须是 tags: 开头,然后换行(这里根据具体情况控制前后空白是否需要匹配)
  • 后面就是正常的标签匹配,然后标签的内容在第一个捕获组中

但是这样只解决了第一个标签,比较尴尬。所以改成:(?<=^tags:\n(?:\s+- [^#]+\n)?) - "#(.*?)"

这里只是改变了前面的断言内容,解读如下:

  • 依然是某一行从 tags: 开头,然后换行
  • (?:) 这是一个匿名捕获组,即不会计入替换时的 $1
    • 内容是 - tagName 这样形式的一行
    • 后面的 ? 表示 0 到多次,同时非贪婪匹配,即匹配尽可能少的次数

这个正则就可以一直匹配到第一个 - "#tagName" 格式的标签了,如此,只需要重复替换直到没有匹配即可。

1 个赞

有一个扩展是自动添加最近编辑时间的,它会自动转换 tag 标签到正确的格式,然后它的设置界面里有一个按钮可以批量更新,缺点就是会添加 created: 与 updated: 这两个属性。

这样确实严谨许多,正则要是能指定字符来缩小查找范围,但不匹配指定字符,在这种情况下就舒服多了

同文件多标签,如果不要求匹配 tags 且确定其他位置没有这种格式标签的话,像楼主这样直接捕获也行 - "(.*?\1)"- "($1)"

请问是哪款插件,我目前用的是 templater ,它的 tp.file.last_modified_date(修改时间)判定很奇怪,明明刚修改过文档内容,时间却没有立即更新,过段时间看它的修改时间又变了

我改过。用的emeditor。但是注意:一定要备份!备份!

用awk多好. sed 难度实际很大.

1 个赞

插件名是 update time on edit

1 个赞