通过定义标题的正则表达式拆分 Markdown 文本文件
Posted
技术标签:
【中文标题】通过定义标题的正则表达式拆分 Markdown 文本文件【英文标题】:Split Markdown text file by regular expression that defines headings 【发布时间】:2021-11-01 07:46:42 【问题描述】:我正在尝试使用命令行程序将较大的文本文件拆分为块:
在定义的正则表达式模式上拆分 由该正则表达式模式中的捕获组定义的文件名文本文件的格式为:
# Title
# 2020-01-01
Multi-line content
goes here
# 2020-01-02
Other multi-line content
goes here
输出应该是这两个文件,文件名和内容如下:
2020-01-01.md ↓
# 2020-01-01
Multi-line content
goes here
2020-01-02.md ↓
# 2020-01-02
Other multi-line content
goes here
我似乎无法正确掌握所有标准。
拆分(分隔符)的正则表达式模式很简单,类似于^# (2020-.*)$
我无法设置一个多行正则表达式模式,该模式越过\n
换行符并在下一次出现分隔符模式时停止。
或者我可以在正则表达式模式上使用csplit
拆分,但我无法使用(2020-.*)
中捕获的内容命名文件
同样适用于 awk split()
或 match()
,无法使其完全正常工作。
我正在寻找一个通用的解决方案,参数是定义块开始(例如# 2020-01-01
)和结束(例如下一个日期标题# 2020-01-02
或EOF
)的正则表达式模式
【问题讨论】:
【参考方案1】:在每个 Unix 机器上的任何 shell 中使用任何 awk:
$ awk '/^# [0-9]/ close(out); out=$2".md" out!=""print > out' file
$ head *.md
==> 2020-01-01.md <==
# 2020-01-01
Multi-line content
goes here
==> 2020-01-02.md <==
# 2020-01-02
Other multi-line content
goes here
如果/^# [0-9]/
不是一个足够的正则表达式,那么将其更改为您喜欢的任何内容,例如/^# [0-9]4(-[0-9]2)2$/
会更严格。 FWIW,尽管如果您没有要求,我根本不会为此使用正则表达式。我会使用:
awk '($1=="#") && (c++) close(out); out=$2".md" out!=""print > out' file
【讨论】:
正则表达式试图确保命令可以处理混乱的输入。那里可能还有其他 1 级标题,它们不是日期、错别字、带有 # 作为 cmets 的围栏代码块。该文件有 331 个这样的标题,但命令输出 327 个文件 通过差异发现,不匹配是由于重复的日期戳,因此文件会被覆盖。我想这个解决方案可以解决这个问题,但我只是编辑源文档来纠正它。 当发现重复的日期时,很容易附加到文件而不是覆盖它,或者在重复的文件名后附加“.1”或其他内容。如果您想要任何这些,请告诉我,我会更新答案。【参考方案2】:使用this regex,这里有一个perl来做到这一点:
perl -0777 -nE 'while (/^\h*#\h*(2020.*)([\s\S]*?(?:(?=(^\h*#\h*2020.*))|\z))/gm)
open($fh, ">", $1.".md") or die $!;
print $fh $1;
print $fh $2;
close $fh;
' file
结果:
head 2020*
==> 2020-01-01.md <==
2020-01-01
Multi-line content
goes here
==> 2020-01-02.md <==
2020-01-02
Other multi-line content
goes here
【讨论】:
以上是关于通过定义标题的正则表达式拆分 Markdown 文本文件的主要内容,如果未能解决你的问题,请参考以下文章