geeknoteで表が書けない
一昨日いれたgeeknote。markdown記法が使えるのはいいんですが、GFMが書けないので表が書けない。ちょっとソースをのぞいてみると、evernoteから読んだテキストを pyton-markdown2 でHTMLに変換している模様。 editor.py の該当部分がこれ。
def textToENML(content, raise_ex=False, format='markdown'): """ Create an ENML format of note. """ if not isinstance(content, str): content = "" try: content = unicode(content, "utf-8") # add 2 space before new line in paragraph for creating br tags content = re.sub(r'([^\r\n])([\r\n])([^\r\n])', r'\1 \n\3', content) if format=='markdown': contentHTML = markdown.markdown(content) soup = BeautifulSoup(contentHTML, 'html.parser') Editor.checklistInSoupToENML(soup)
なんでできんのじゃ
python-markdownを調べてみると、現行バージョンのpython-markdown2ではGFMもちゃんと扱えて、表を作成する場合には markdown()にextras引数を配列で与えればいい模様。
contentHTML = markdown.markdown(content,extras=["tables"])
対話式のpythonで試してみる。
$ python Python 2.7.6 (default, Jun 22 2015, 18:00:18) [GCC 4.8.2] on linux2 Type "help", "copyright", "credits" or "license" for more information. >>> import markdown2 >>> text="|title|title|\n|----|----|\n|col1|col2|\n|col3|col4|\n" >>> print text |title|title| |----|----| |col1|col2| |col3|col4| >>> markdown2.markdown(text)← extrasを与えない場合 u'<p>|title|title|\n|----|----|\n|col1|col2|\n|col3|col4|</p>\n' >>> markdown2.markdown(text,extras=["tables"]) ←extrasでtablesを指定した場合。ちゃんと表形式のHTMLに変換している u'<table>\n<thead>\n<tr>\n <th>title</th>\n <th>title</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n <td>col1</td>\n <td>col2</td>\n</tr>\n<tr>\n <td>col3</td>\n <td>col4</td>\n</tr>\n</tbody>\n</table>\n' >>>
ソースをいじる
本当ならば、geeknote setting extras="tables"とかって指定してからできるようにすればいいんだろうけどね。面倒なのでeditor.pyを直接いじっちゃう。
markdown()を読んでいるところを以下のように変更。
contentHTML = markdown.markdown(content,extras=["tables"])
試してみる
さっそくやってみる。。うまくいかない。上記でextrasを指定しなかった時と同じ結果になります。なんでじゃ。
なんか余計なことやっとんな
ソースを眺めること2時間。対話式で検証したときと何がちがうんだと検証した結果、makrdown()を読んでいる4行前の正規表現に原因があることを発見。この部分です。
# add 2 space before new line in paragraph for creating br tags content = re.sub(r'([^\r\n])([\r\n])([^\r\n])', r'\1 \n\3', content)
コメントで注釈している通り、改行の前に2つのスペースを挿入しています。
conetntがこうだったら、
# hoge ## fuga * item * item
この正規表現での変換でこうなります。□はスベース。
# hoge□□ ## fuga□□ * item□□ * item
この変換のためにGFMで表形式と思って書いたところが、表形式と認識されないことが原因でした。
ではこうしましょう
いろんな回避策は思いつくんですが、単純に。表形式のGFMの場合、|\nで終わっていると仮定して、その場合にはスペースを入れない*1とする。正規表現での変換はこう。
content = re.sub(r'([^\r\n|])([\r\n])([^\r\n])', r'\1 \n\3', content)
パイプがあって、改行がある場合はマッチしないので、変換されない。
これでようやく表形式で保存できました。
ついでに
保存するときにBeatifulSoupのワーニングがでるのを修正。一昨日入れたhtml2text()の文法違いも合わせたdiffはこちら。本当はgithubへpushするべきなんだろうけどな。
79c79 < soup = BeautifulSoup(contentENML.decode('utf-8')) --- > soup = BeautifulSoup(contentENML.decode('utf-8'),'html.parser') 101c101 < content = html2text.html2text(str(soup).decode('utf-8'), '', 0) --- > content = html2text.html2text(str(soup).decode('utf-8'), '') 169c169 < content = re.sub(r'([^\r\n])([\r\n])([^\r\n])', r'\1 \n\3', content) --- > content = re.sub(r'([^\r\n|])([\r\n])([^\r\n])', r'\1 \n\3', content) 171c171 < contentHTML = markdown.markdown(content) --- > contentHTML = markdown.markdown(content,extras=["tables"])
*1:実際の文法ではパイプで終わってなくても可