マークダウンで作った本文からタイトルだけ取り出して目次を作りたいことがあります。これは「#」で始まる行を抜き出したり、Markdown TOCのようなプラグインを使うとできますが、Pythonのようにコードに「#」が含まれているケース(Pythonの場合はコメント)はプラグインの動作が正常にいかないことがあります。その対処法を見ていきます。
目次
以下のマークダウンから目次を作ってみましょう。
次のような目次を作って欲しいのです。
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
望んだ通りのができたー!! おわり。
あとは好みでページ数をつけたり(これはアドホックに値入れて打ち込むしかないです)すれば本の目次になったりします。こんな感じで薄い本を作りました。以上。