こしあん
2020-03-21

マークダウンから正規表現で目次を作る


1k{icon} {views}

マークダウンで作った本文からタイトルだけ取り出して目次を作りたいことがあります。これは「#」で始まる行を抜き出したり、Markdown TOCのようなプラグインを使うとできますが、Pythonのようにコードに「#」が含まれているケース(Pythonの場合はコメント)はプラグインの動作が正常にいかないことがあります。その対処法を見ていきます。

マークダウンサンプル

以下のマークダウンから目次を作ってみましょう。

次のような目次を作って欲しいのです。

  • 第1章 タイトル
    • 1.1 見出し1
    • 1.2 見出し2
    • 1.3 見出し3
  • 第2章 タイトル
    • 2.1 見出し1

h3相当の「ああああ」と「いいい」は今含まないものとします。ここで問題となるのは、コード行の「#」を無視しなければならない、つまり「コメント」と「コメント2」を含んではいけないのです。

正規表現でコードを消す

目次を作る際にコード行は一切必要がないので消してしまいましょう。頑張って正規表現で作ってみました。

import re

def create_index():
    # ファイルを読み込む
    with open("sample_markdown.md", encoding="utf-8") as fp:
        data = fp.read()
    # 正規表現でコード行を消す
    data = re.sub(r"```((?!`).|\r|\n)+```", "", data)
    print(data)

if __name__ == "__main__":
    create_index()

結果は次のようになります。

# 第1章 タイトル
## 1.1 見出し1
### ああああ
ここに本文が入る



### いいい
ここに本文が入る。は適当な変数。

## 1.2 見出し2
ここに本文が入る

## 1.3 見出し3
ここに本文が入る

# 第2章 タイトル
## 2.1 見出し1

コードが消えましたね。これで第一段階クリアです。

見出しを作る

あんまきれいじゃないコードですけど、h1, h2相当の見出しのみ箇条書きで出すスタイルです。

import re

def create_index():
    # ファイルを読み込む
    with open("sample_markdown.md", encoding="utf-8") as fp:
        data = fp.read()
    # 正規表現でコード行を消す
    data = re.sub(r"```((?!`).|\r|\n)+```", "", data)

    header_lines = ["# 目次"]
    for l in data.splitlines():
        if re.match(r"#{1,2} ", l):
            if l.startswith("# "):
                x = l.replace("# ", "* ")
                header_lines.append(x)
            else:
                header_lines.append(l.replace("## ", "    + "))
    header_lines.append("")

    with open("index.md", "w", encoding="utf-8") as fp:
        fp.write("\n".join(header_lines))

if __name__ == "__main__":
    create_index()

index.mdの出力は次のようになります。

# 目次
* 第1章 タイトル
    + 1.1 見出し1
    + 1.2 見出し2
    + 1.3 見出し3
* 第2章 タイトル
    + 2.1 見出し1

望んだ通りのができたー!! おわり。

あとは好みでページ数をつけたり(これはアドホックに値入れて打ち込むしかないです)すれば本の目次になったりします。こんな感じで薄い本を作りました。以上。



Shikoan's ML Blogの中の人が運営しているサークル「じゅ~しぃ~すくりぷと」の本のご案内

技術書コーナー

北海道の駅巡りコーナー


Add a Comment

メールアドレスが公開されることはありません。 が付いている欄は必須項目です