.mdファイルをScrapboxの書式に変換するスクリプトをpythonで作った

## はじめに

* Qiitaに投稿するときはよくマークダウンでローカルに下書きしています．
    * 論文の要約をマークダウンでメモする用途を想定しています
* [Scrapbox](https://scrapbox.io)が見やすい&メモしやすい&リンクしやすい のでメモ代わりによく使うのですが，マークダウン形式は対応していないので，マークダウンファイルをscrapboxでみやすい形式に変換するスクリプトを書きました.
* python3

## 変換する対象

### 箇条書き

```markdown:入力.md
* イメージキャプショニングはビジュアルシーンに対して自然言語の説明をつけるタスク
    * この分野ではここ５年でニューラルencoder-decoderが人気
        * sotaはCNNのエンコーダ，LSTM(やTransformer)のデコーダ，とattention機構で構成されている
```
マークダウンでは`*`や`-`で書きます．
scrapboxではスペース１文字でインデント+バレット(黒丸●のこと)1個分になるので，スペースに置き換わります．

```text:出力.txt
 イメージキャプショニングはビジュアルシーンに対して自然言語の説明をつけるタスク
  この分野ではここ５年でニューラルencoder-decoderが人気
   sotaはCNNのエンコーダ，LSTM(やTransformer)のデコーダ，とattention機構で構成されている
```

![スクリーンショット 2020-04-29 21.10.08.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/296108/7c4ea036-e227-e3b3-d00d-91fe4af86679.png)
scrapbox上ではこのように見えます


### 角括弧[]

```markdown:入力.md
[27]はCNN encoder, LSTM decoderからなるモデルを提案
```

論文の引用に使う角括弧[]を丸括弧()に変換します
この理由はscrapboxでは角括弧[]は記事間のリンクを意味するからです

```text:出力.txt
(27)はCNN encoder, LSTM decoderからなるモデルを提案

```


### タイトル


```markdown:入力.md
## 2. 関連研究

### 2.1. Image Captioning
```

マークダウンでは見出しとしてh1 ~ h6までを`#`を複数続けることで表現します．
scrapboxには見出しはないので，代わりに太字を使います．太字は角括弧[]で二重に囲みます．`[[強調したい文字列]]`

```text:出力.txt
[[ 2. 関連研究]]

[[ 2.1. Image Captioning]]
```

![スクリーンショット 2020-04-29 21.11.33.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/296108/3e5d9448-28bf-bd35-e433-3c6a135205e3.png)
scrapbox上ではこのように見えます

### 数式


```markdown:入力.md
$f_t = \sigma(W_f \cdot [h_{t-1}, x_t] + b_f)$
```

マークダウンでは`$数式$`で１行内での数式を表現できます．
scrapboxでは同じことが`[$ 数式]`でできます．

```text:出力.txt
[$ f_t = \sigma(W_f \cdot (h_{t-1}, x_t) + b_f)]
```

![スクリーンショット 2020-04-29 21.12.33.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/296108/219c1d25-3b83-cf57-b612-75f5f07ac9bb.png)
scrapbox上ではこのように見えます


ちなみにscrapboxでは`\tag{1}`などの数式番号を入れると１行におさまらず，２行になってしまいます．今回はこれに対応できていません．

### 太字


```markdown:入力.md
**強調のテスト**
```

マークダウンでは`**強調したい文字**`などの方法で太字表現できます．
scrapboxでは先述の通り，`[[強調したい文字列]]`になります．

```text:出力.txt
[[強調のテスト]]
```


## ソースコード

愚直に`re`と`str.replace()`で文字列を置き換えるだけです．
変なところあったら教えていただけると助かります．

エスケープ`\`の影響でシンタックスハイライトの色が消えてしまった・・・

```python:md2scrapbox.py

import os
import argparse
import re

parser = argparse.ArgumentParser()
parser.add_argument("in_file")
args = parser.parse_args()

sentence = "" # output
tab = "    " 
space = " "
bullet = "* "
strong = r"\*\*.*\*\*.?"
title = r"#*"
math = r"\$[^\$]*\$"

with open(args.in_file, "r") as f:
    lines = f.readlines()
for line in lines:

    # blaket    
    line = line.replace("[", "(")
    line = line.replace("]", ")")


    # indentation
    for m in re.finditer(tab, line):
        line = re.sub(tab, space, line)
    line = line.replace(bullet, space, 1)


    # title
    m = re.search(title, line)
    if len(m.group()) > 0:
        line = "[[" + line[m.end():].replace("\n", "") + "]]\n"
        
        
    # math
    m = re.findall(math, line)
    if m:
        for matched in m:
            m2 = re.sub(r"^\$", "[$ ", matched)
            m2 = re.sub(r"\$$", "]", m2)
            line = line.replace(matched, m2)
        sentence += line
        continue
    else:
        # enphasis
        m = re.findall(strong, line)
        if m:
            for matched in m:
                m2 = re.sub(r"^\*\*", "[[", matched)
                m2 = re.sub(r"\*\*$", "]]", m2)
                line = line.replace(matched, m2)
        sentence += line

print("==========")
print(sentence)

dirname = os.path.dirname(args.in_file)
name = os.path.basename(args.in_file)
name, ext = os.path.splitext(name)
name = name + "_scrapbox.txt"
name = os.path.join(dirname, name)
print(name)

with open(name, "w") as f:
    f.write(sentence)

```

### 使い方

```bash
python md2scrapbox.py path/to/some_file.md
```

変換結果は入力と同じ場所に名前を変えて保存されます
上の例だと`path/to/some_file_scrapbox.txt`になります．

あとは出来上がった文字列をscrapboxに貼るだけです．