この連載は、『PythonでMarkdownからEPUBをつくろう』を一部抜粋して編集したものです。
本編には、全てのソースコードや、生成する原稿のサンプルが付属しています。ぜひ、こちらもご購入ください。
姉妹版の『PythonとPygameで作る レトロ風RPG 全コード』もあります。
≫ 目次に戻る mod/doc/md.py
では、Markdownの変換をおこないます。
gen-epub/
main.py
mod/
doc/
md.py
1import re, markdown
2
3# Markdownの初期化
4md = markdown.Markdown(extensions=[
5 'attr_list', # 属性追加
6 'tables', # GitHub形式のtable領域
7 'fenced_code', # ```~```形式のコード領域
8 'md_in_html', # HTMLタグ内にMarkdownを記述
9 'sane_lists', # ulとolを別のリストに
10])
11
12# Markdownの変換
13def convert(t):
14 # Markdown変換
15 # 全角インデントが消されるので回避して復帰する
16 t = re.sub('(?m)^( +)', '\b\1\b', t) # 回避
17 t = md.convert(t)
18 t = re.sub('\b( +)\b', '\1', t) # 復帰
19
20 # tableタグの位置揃えでstyleが使われるのでclassに変換
21 t = re.sub('style="text-align: (.+?);"', r'class=""', t)
22
23 # 画像のみの行を調整
24 t = re.sub('<p>(<img .+?>)</p>', r'<div class="image-full"></div>', t)
25 return t
このファイルは2つの部分に分かれています。前半が初期化で、後半が実際の変換です。そのため分けて解説します。
まずは初期化部分です。
1import re, markdown
2
3# Markdownの初期化
4md = markdown.Markdown(extensions=[
5 'attr_list', # 属性追加
6 'tables', # GitHub形式のtable領域
7 'fenced_code', # ```~```形式のコード領域
8 'md_in_html', # HTMLタグ内にMarkdownを記述
9 'sane_lists', # ulとolを別のリストに
10])
pip install Markdown
でインストールしたMarkdownパッケージをimport markdown
でインポートします。
ここでは設定を引数にして初期化したあと変換に利用します。事前の初期化はmd = markdown.Markdown(extensions=[])
でおこなえます。以降は、変数md
を利用して変換をおこなえます。
初期化の際に、いくつかの拡張機能を有効にします。ここで利用する拡張機能をまとめておきます。
attr_list
変換したHTMLに属性を追加できます。属性は次のように書きます。
要素{: #someid .someclass somekey='some value' }
#someid
はid="someid"
に、.someclass
はclass="someclass"
に、somekey='some value'
はそのまま、HTMLタグの属性として追加されます。
tables
GitHub形式のtable領域を使えるようにします。table領域は次のように書きます。
|ヘッダー1|ヘッダー2|ヘッダー3|
|:--|:--|:--|
|セル1-1|セル1-2|セル1-3|
|セル2-1|セル2-2|セル2-3|
:--
は列の左寄せ、:--:
は中央、--:
は右寄せを意味します。
fenced_code
バックスラッシュ3つで囲んだコード領域を使えるようにします。
```
複数行のコード領域。
複数行のコード領域。
```
先頭のバックスラッシュ3つのあとに、属性の情報を追加できます。
``` { .lang #myid .class1 .class2 style="color: #333" }
print('rat')
print('cat')
print('dog')
```
.lang
は、生成される<code>
タグに、class="language-lang"
の属性を加えます。
2つめ以降のクラス(.class1
、.class2
)は、生成される<pre>
タグに、class="class1 class2"
の属性を加えます。
#myid
は、生成される<pre>
タグに、id="myid"
を加えます。
IDとクラスの記述順は自由です。
上のコード領域は、次のように変換されます。
<pre id="myid" class="class1 class2"><code class="language-lang">print('rat')
print('cat')
print('dog')
</code></pre>
コードにclass="language-lang"
の属性を加えるだけなら、次の書き方も使えます。
``` lang
```
md_in_html
HTMLタグ内にMarkdownを書けるようになります。この機能を使うには、HTMLタグにmarkdown="1"
という属性を書く必要があります。
sane_lists
<ul>
のリスト(箇条書きリスト)と<ol>
のリスト(連番リスト)が混在して並んでいるときは、別のリストとしてまとめます
デフォルトでは、先に書いたものに統合されてしまいます。
変換はmd.convert(t)
でおこなえます。ただ、そのままでは問題があるので、いくつか処理を加えています。
11
12# Markdownの変換
13def convert(t):
14 # Markdown変換
15 # 全角インデントが消されるので回避して復帰する
16 t = re.sub('(?m)^( +)', '\b\1\b', t) # 回避
17 t = md.convert(t)
18 t = re.sub('\b( +)\b', '\1', t) # 復帰
19
20 # tableタグの位置揃えでstyleが使われるのでclassに変換
21 t = re.sub('style="text-align: (.+?);"', r'class=""', t)
22
23 # 画像のみの行を調整
24 t = re.sub('<p>(<img .+?>)</p>', r'<div class="image-full"></div>', t)
25 return t
Markdownパッケージは、本文の冒頭にある半角スペースと全角スペースを除去します。日本語の文章を書くときに、全角スペースで1文字下げている場合には、この全角スペースが全てなくなってしまいます。
この除去を回避するための処理を加えてます。
1t = re.sub('(?m)^( +)', '\b\1\b', t) # 回避
2t = md.convert(t)
3t = re.sub('\b( +)\b', '\1', t) # 復帰
上の1行目と3行目がその処理です。正規表現の置換re.sub()
を使い、先頭が全角スペース1つ以上の場合は\b
(ベル)で囲います。そしてMarkdown変換後に\b
を除去します。
1行目で出てくる(?m)
は^
と$
の記号の挙動を変えるフラグです。通常では^
は文章全体の先頭を、$
は文章全体の末尾を表します。(?m)
フラグを付けると、^
は各行の先頭を、$
は各行の末尾を表します。
また( )
(丸括弧)で囲んだ部分は、置換テキスト内で利用できます。1つめの丸括弧内は\1
、2つ目の丸括弧内は\2
として利用できます。
続いて、style="text-align: right;"
のような属性部分をclass="right"
のように置換します。
これはMarkdownパッケージが、テーブルを作る際に、左寄せ、中央、右寄せの設定を直接style
属性に書き込むためです。この書き方はKindleでエラーが出るために修正しています。
最後に、画像のみの行のタグを下のように調整しています。
<p><img="~" /></p>
<div class="image-full"><img="~" /></div>
この連載は、『PythonでMarkdownからEPUBをつくろう』を一部抜粋して編集したものです。
本編には、全てのソースコードや、生成する原稿のサンプルが付属しています。ぜひ、こちらもご購入ください。
姉妹版の『PythonとPygameで作る レトロ風RPG 全コード』もあります。