Разделить текстовый файл Markdown по регулярному выражению, определяющему заголовки

Я пытаюсь использовать программу командной строки, чтобы разбить более крупный текстовый файл на куски с помощью:

  • разделить на определенный шаблон регулярного выражения
  • имена файлов, определенные группой захвата в этом шаблоне регулярного выражения

Текстовый файл имеет формат:

      # 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)

2 ответа

Используя любой awk в любой оболочке на каждом Unix-компьютере:

      $ 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

Используя это регулярное выражение , вот 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
Другие вопросы по тегам