通过定义标题的正则表达式拆分 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-02EOF)的正则表达式模式

【问题讨论】:

【参考方案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 文本文件的主要内容,如果未能解决你的问题,请参考以下文章

markdown 字符串拆分与正则表达式为中国符号 -

通过正则表达式拆分字符串[重复]

Pandas 正则表达式拆分字符和组

正则表达式 .net 拆分

markdown 尖叫青蛙自定义提取的正则表达式Cheatsheet

python 正则表达式通过标点符号进行拆分