Markdown. Сдвиг уровня заголовков

Markdown. Сдвиг уровня заголовков

2026-01-02 · 8 мин. для прочтения

Markdown. Сдвиг уровня заголовков

Содержание

1 Сдвиг на один уровень вверх

  • Регулярное выражение добавляет одну решётку # к любому количеству существующих решёток в начале строки.

1.1 Регулярное выражение

^(#+)(.*)$

1.2 Замена

$1#$2

1.3 Как это работает

1.3.1 Регулярное выражение

  • ^ — начало строки (гарантирует, что мы меняем только заголовки, а не # внутри текста).
  • (#+)— захватывающая группа:
    • # — символ решётки;
    • + — одно или более повторений (любая длина последовательности # в начале строки).
  • (.*) — захватывающая группа: весь остальной текст строки (содержание заголовка).
  • $ — конец строки.

1.3.2 Замена

  • $1 — первая захваченная группа (исходные решётки);
  • # — добавляем ещё одну решётку (повышаем уровень);
  • $2 — вторая захваченная группа (текст заголовка).

1.4 Пример

  • Было:
# Заголовок 1
## Заголовок 2
### Заголовок 3
#### Заголовок 4
##### Заголовок 5
###### Заголовок 6
####### Заголовок 7  ← нестандартный, но валидный для некоторых парсеров
  • Стало:
## Заголовок 1
### Заголовок 2
#### Заголовок 3
##### Заголовок 4
###### Заголовок 5
####### Заголовок 6
######## Заголовок 7

1.5 Замечания

  • H6 и выше:

    • Стандарт Markdown поддерживает до H6 (######).
    • Если у вас есть ####### (7 решёток), замена создаст ######## (8 решёток). Это невалидный синтаксис по спецификации, но некоторые парсеры (например, GitHub) его обрабатывают.
  • Пробелы после #:

    • Шаблон работает независимо от наличия пробелов:
      • #Заголовок##Заголовок
      • # Заголовок## Заголовок
  • Заголовки с замыкающими #:

    • Если используются формы вроде # Заголовок #, сначала уберите замыкающие # отдельным поиском/заменой:

      ^(#+)(.*?)\s*#*\s*$
      
      • Замена: $1$2.

2 Сдвиг на один уровень вниз

  • Для понижения уровня заголовков Markdown (H2 → H1, H3 → H2 и т. д.) нужно убрать одну решётку # из начала строки.
  • При этом заголовки H1 (# ...) должны остаться без изменений (иначе получится невалидный синтаксис).

2.1 Регулярное выражение

^(#+)(#)(.*)$

2.2 Замена

$1$3

2.3 Как это работает

2.3.1 Регулярное выражение

  • ^ — начало строки (гарантирует, что меняем только заголовки).
  • (#+) — первая захватывающая группа:
  • #+ — одна или более решёток (захватывает все # в начале, кроме последней).
  • (#) — вторая захватывающая группа:
    • ровно одна решётка # (которую мы уберём).
  • (.*) — третья захватывающая группа:
    • весь остальной текст строки (содержание заголовка).
  • $ — конец строки.

2.4 Замена

  • $1 — первые решётки (без последней);
  • $3 — текст заголовка (пропускаем $2, т. к. именно её удаляем).

2.5 Пример

  • Было:
# Заголовок 1          ← не изменится (H1)
## Заголовок 2         ← станет H1
### Заголовок 3        ← станет H2
#### Заголовок 4       ← станет H3
##### Заголовок 5      ← станет H4
###### Заголовок 6     ← станет H5
####### Заголовок 7   ← станет H6 (если парсер поддерживает)
  • Стало:
# Заголовок 1
# Заголовок 2
## Заголовок 3
### Заголовок 4
#### Заголовок 5
##### Заголовок 6
###### Заголовок 7

2.6 Замечания

  • H1 остаётся без изменений:

    • Шаблон (#+)(#) требует минимум две решётки в начале строки.
    • Строки вида # Заголовок (H1) не совпадут и не изменятся.
  • Пробелы после #:

    • Шаблон работает независимо от пробелов:
      • ##Заголовок#Заголовок
      • ## Заголовок# Заголовок
  • Заголовки с замыкающими #:

    • Если есть формы вроде ## Заголовок ##, сначала уберите замыкающие # отдельным поиском/заменой:
      ^(#+)(.*?)\s*#*\s*$
      
    • Замена: $1$2.
  • Ограничение до H6 (опционально):

    • Если нужно не опускать ниже H6, используйте:
      ^(#{2,6})#(.*)$
      
    • Замена: $1$3.
    • Это понизит H2–H6, но оставит H1 и H7+ без изменений.

3 Регулярные выражения для Emacs

  • Регулярные выражения в нотации Emacs.
  • Ключевые особенности:
    • Экранирование групп: \( и \) вместо ( и );
    • Экранирование квантификаторов: \+ вместо +, \{1,5\} вместо {1,5};
    • Обратные ссылки: \1, \2 вместо $1, $2.

3.1 Сдвиг заголовков вверх (H1 → H2, H2 → H3 и т. д.) (c ограничением по уровню)

  • Регулярное выражение (Emacs)
^\(#\{1,5\}\)\(.*\)$
  • Замена (Emacs)
\1#\2

3.1.1 Пояснение

  • ^ — начало строки;
  • \(#\{1,5\}\) — захватываем от 1 до 5 решёток;
  • \(.*\) — захватываем остальную часть строки;
  • $ — конец строки;
  • \1#\2 — вставляем первую группу, добавляем #, вставляем вторую группу.

3.2 Сдвиг заголовков вверх (без ограничения по уровню)

  • Регулярное выражение (Emacs)
^\(#+\)\(.*\)$
  • Замена (Emacs)
\1#\2

3.2.1 Пояснение

  • \(#+\) — захватываем одну или более решёток;
  • остальное — аналогично предыдущему.

3.3 Сдвиг заголовков вниз (H2 → H1, H3 → H2 и т. д.; H1 не меняется)

  • Регулярное выражение (Emacs):
^\(#+\)#\(.*\)$
  • Замена (Emacs):
\1\2

3.3.1 Пояснение

  • \(#+\) — захватываем все решётки, кроме последней;
  • # — одна решётка, которую удаляем;
  • \(.*\) — остальная часть строки;
  • \1\2 — вставляем первую и третью группы (вторую пропускаем).

3.4 Сдвиг заголовков вниз с ограничением до H6 (H2–H6 понижаем, H1 и H7+ не трогаем)

  • Регулярное выражение (Emacs):
^\(#\{2,6\}\)#\(.*\)$
  • Замена (Emacs):
\1\2

3.4.1 Пояснение

  • \(#\{2,6\}\) — захватываем от 2 до 6 решёток (т. е. уровни H2–H6);
  • # — удаляемая решётка;
  • \(.*\) — текст заголовка;
  • \1\2 — склеиваем первую и третью группы.

3.5 Как применять в Emacs

  • Откройте файл в Emacs.
  • Нажмите M-x replace-regexp (или C-M-% для query-replace-regexp).
  • Введите регулярное выражение и замену в формате выше.
  • Нажмите Enter — Emacs предложит поочерёдно подтвердить замены.

3.6 Примечания

  • Экранирование: в Emacs +, {, }, ( и ) требуют обратного слеша \.
  • Группы: \( и \) создают группы, \1, \2 ссылаются на них.
  • Пробелы и табуляции: если в заголовках есть пробелы после #, выражения работают корректно (пробелы входят в .*).
  • Замыкающие #: если есть формы вроде # Заголовок #, сначала уберите замыкающие # отдельным поиском:
    • Regexp: ^\(#+\)\(.*?\)\s*#*\s*$
    • Replace: \1\2

4 Регулярные выражения для sed

4.1 Синтаксис sed для замены по регулярным выражениям

  • Общий формат:

    sed -i 's/шаблон/замена/g' файл.md
    
    • -i — редактирование файла «на месте» (in‑place);
    • s/ — команда замены (substitute);
    • /шаблон/замена/ — шаблон поиска и строка замены;
    • g — глобальная замена (все совпадения в строке; для заголовков обычно не нужно, т. к. одно совпадение на строку);
    • '...' — кавычки, экранирующие спецсимволы для оболочки.
  • В BSD‑версии sed требуется суффикс после -i (например, -i ''). В GNU sed (Linux) можно -i без суффикса.

4.2 Сдвиг заголовков вверх (H1 → H2, H2 → H3 и т. д.)

4.2.1 С ограничением до H5 (H6 не меняется)

  • Команда:
sed -i '' 's/^\(#\{1,5\}\)\(.*\)$/\1#\2/g' файл.md
  1. Пояснение

    • ^ — начало строки;
    • \(#\{1,5\}\) — захватывающая группа: от 1 до 5 решёток #;
    • \(.*\) — захватывающая группа: весь остальной текст строки;
    • $ — конец строки;
    • \1#\2 — подстановка: первая группа + одна решётка + вторая группа.
  1. Пример

    • Было: # Заголовок → Стало: ## Заголовок
    • Было: ##### Заголовок → Стало: ###### Заголовок
    • ###### Заголовок (H6) → не меняется.

4.2.2 Без ограничения по уровню (любой H → H+1)

  • Команда:
sed -E -i 's/^(#+)(.*)$/\1#\2/g' файл.md
  • Пояснение:
    • (#+) захватывает одну или более решёток (не ограничиваясь 5).
  1. Пример

    • ####### Заголовок (7 решёток) → ######## Заголовок (8 решёток).

4.3 Сдвиг заголовков вниз (H2 → H1, H3 → H2 и т. д.; H1 не меняется)

4.3.1 Без ограничений (любой H≥2 → H−1)

  • Команда:
sed -E -i '' 's/^(#+)#(.*)$/\1\2/g' файл.md
  1. Пояснение

    • (#+) — захватываем все решётки, кроме последней;
    • # — одна решётка, которую удаляем;
    • (.*) — текст заголовка;
    • \1\2 — склеиваем первую и третью группы (вторая — удаляемая решётка).
  1. Пример

    • ## Заголовок# Заголовок
    • ### Заголовок## Заголовок
    • # Заголовок (H1) → не меняется (требуется минимум две решётки).

4.3.2 С ограничением до H6 (H2–H6 → H−1, H1 и H7+ не меняются)

  1. Команда

    sed -E -i 's/^(#{2,6})#(.*)$/\1\2/g' файл.md
    
    • Отличие:
      • (#{2,6}) захватывает от 2 до 6 решёток.
  1. Пример

    • ## Заголовок (H2) → # Заголовок (H1);
    • ###### Заголовок (H6) → ##### Заголовок (H5);
    • ####### Заголовок (H7) → не меняется.

4.4 Итоговые команды

4.4.1 Сдвиг вверх (без ограничений)

sed -E -i 's/^(#+)(.*)$/\1#\2/g' файл.md

4.4.2 Сдвиг вниз (без ограничений)

sed -E -i 's/^(#+)#(.*)$/\1\2/g' файл.md

4.4.3 Сдвиг вверх (до H5)

sed -E -i '' 's/^(#{1,5})(.*)$/\1#\2/g' файл.md

4.4.4 Сдвиг вниз (до H6)

sed -E -i 's/^(#{2,6})#(.*)$/\1\2/g' файл.md

4.4.5 Примечания

  • Пробелы после #:

    • Все приведённые команды работают независимо от наличия пробелов после решёток:

    • ##Заголовок#Заголовок;

    • ## Заголовок# Заголовок.

  • Замыкающие # (форма # Заголовок #):

    • Если такие есть, сначала уберите их отдельной командой:
      sed -E -i 's/^(#+)(.*?)\s*#*\s*$/\1\2/g' файл.md
      
    • Это удалит все # в конце строки после пробела.
  • Тестирование перед применением:

    • Чтобы увидеть результат без изменения файла, опустите -i:
      sed -E 's/^(#+)(.*)$/\1#\2/g' файл.md
      
    • Вывод отобразится в терминале.