簡易なおれおれマークダウン 2019秋


はじめに

以前に 簡易なHTMLパーサ 2018秋 を作成しました。

以降、HTML形式のものを作るときは、まずYAML形式で作成。

それから自作のツールezhtml.pyを使って、YAML形式からHTML形式に変換するようになりました。

ですがここにきて、YAML形式の作成も「かったるく」なってしまいました。

例えば、次のような既存のテキストの場合

foo.txt

$ cat foo.txt
Python2とPython3での日本語文字列対応について

  毎回、同じようにつまづいて、同じような感じで対応してます。
  なので、いいかげん自分に判りやすいようにまとめておきます。
  日本語対応といっても、ソースコード中に日本語を書くつもりはありません。
  データはYAML形式のファイルで用意。
  そして、YAML形式データファイル中の文字列を、UTF-8で日本語に置き換えようとして、
  毎回「うぅっ」とうなってます。

結論

  日本語を含む文字列処理で .foramt() や .join() を使いたい

    Python2 では日本語を含む文字列は .encode('utf-8')して UTF-8 で保持。
    Python3 では日本語の有無に関係なく、素直にstrのままでよし。

  日本語を含むUTF-8のテキストを標準入力、標準出力で扱いたい

    Python2 では素直に sys.stdin/sys.stdout を read/write。
    Python3 では sys.stdin.buffer , sys.stdout.buffer を使う。
    Python2 の世界には .buffer は存在しないので注意。

まずはYAML形式で

foo.yaml

$ cat foo.yaml
html:
- head:
  - meta http-equiv="Content-Type" content="text/html;charset=iso-2022-jp": /
  - title: py23str
  - style: 'pre{ background: lightgray; }'
  - style: 'img{ max-width: 100%; height: auto; }'
  - style: 'h3{ border-left: solid gray; padding: 1em 0.5em; }'

- body:
  - h1: Python2とPython3での日本語文字列対応について

  - p:
    - 毎回、同じようにつまづいて、同じような感じで対応してます。
  - p:
    - なので、いいかげん自分に判りやすいようにまとめておきます。
  - p:
    - 日本語対応といっても、ソースコード中に日本語を書くつもりはありません。
  - p:
    - データはYAML形式のファイルで用意。
  - p:
    - そして、YAML形式データファイル中の文字列を、UTF-8で日本語に置き換えようとして、
    - 毎回「うぅっ」とうなってます。

  - h2: 結論

  - h3: 日本語を含む文字列処理で .foramt() や .join() を使いたい
  - p:
    - Python2 では日本語を含む文字列は .encode('utf-8')して UTF-8 で保持。
  - p:
    - Python3 では日本語の有無に関係なく、素直にstrのままでよし。

  - h3: 日本語を含むUTF-8のテキストを標準入力、標準出力で扱いたい
  - p:
    - Python2 では素直に sys.stdin/sys.stdout を read/write。
  - p:
    - Python3 では sys.stdin.buffer , sys.stdout.buffer を使う。
  - p:
    - Python2 の世界には .buffer は存在しないので注意。

を作成しておいて

$ ./ezhtml.py y < foo.yaml | nkf -j > foo.html

$ nkf -g foo.html
ISO-2022-JP

$ cat foo.html | nkf -u
<html><head><meta http-equiv="Content-Type" content="text/html;charset=iso-2022-jp">
<title>py23str</title>
<style>pre{ background: lightgray; }</style>
<style>img{ max-width: 100%; height: auto; }</style>
<style>h3{ border-left: solid gray; padding: 1em 0.5em; }</style></head>
<body><h1>Python2とPython3での日本語文字列対応について</h1>
<p>毎回、同じようにつまづいて、同じような感じで対応してます。</p>
<p>なので、いいかげん自分に判りやすいようにまとめておきます。</p>
<p>日本語対応といっても、ソースコード中に日本語を書くつもりはありません。</p>
<p>データはYAML形式のファイルで用意。</p>
<p>そして、YAML形式データファイル中の文字列を、UTF-8で日本語に置き換えようとして、
毎回「うぅっ」とうなってます。</p>
<h2>結論</h2>
<h3>日本語を含む文字列処理で .foramt() や .join() を使いたい</h3>
<p>Python2 では日本語を含む文字列は .encode('utf-8')して UTF-8 で保持。</p>
<p>Python3 では日本語の有無に関係なく、素直にstrのままでよし。</p>
<h3>日本語を含むUTF-8のテキストを標準入力、標準出力で扱いたい</h3>
<p>Python2 では素直に sys.stdin/sys.stdout を read/write。</p>
<p>Python3 では sys.stdin.buffer , sys.stdout.buffer を使う。</p>
<p>Python2 の世界には .buffer は存在しないので注意。</p></body></html>

に変換。

foo.html

このように表示されます。

ですが、このYAML形式を作成するのが結構ツライです。

できれば foo.txt から foo.yaml の形式に変換できないものか...

世の中にはマークダウン形式の規格・仕様は存在します。

ですが、ここはひとつ目をつむって「簡易おれおれマークダウン」な仕様の 変換ツールを作ってみる事にします。


headとbody

foo.yaml の段階で、headとbodyに分かれてます。

そしてbody以降は、最低スペース2つの字下げが必ず入ってます。

headでfoo.txtからの固有の情報は

- title: py23str

だけで、あとはほぼお決まりで固定です。

headのtilteはあとで編集するとして、bodyだけ何とか変換するように目指してみます。

まずは

foo_head.yaml

を用意。

$ cat foo_head.yaml
- meta http-equiv="Content-Type" content="text/html;charset=iso-2022-jp": /
- title: py23str
- style: 'pre{ background: lightgray; }'
- style: 'img{ max-width: 100%; height: auto; }'
- style: 'h3{ border-left: solid gray; padding: 1em 0.5em; }'

そして foo.txt から、これから作成を目指すツールで、何とか foo_body.yaml を自動生成します。

$ cat foo_body.yaml
- h1: Python2とPython3での日本語文字列対応について

- p:
  - 毎回、同じようにつまづいて、同じような感じで対応してます。
- p:
  - なので、いいかげん自分に判りやすいようにまとめておきます。
- p:
  - 日本語対応といっても、ソースコード中に日本語を書くつもりはありません。
- p:
  - データはYAML形式のファイルで用意。
- p:
  - そして、YAML形式データファイル中の文字列を、UTF-8で日本語に置き換えようとして、
  - 毎回「うぅっ」とうなってます。

- h2: 結論

- h3: 日本語を含む文字列処理で .foramt() や .join() を使いたい
- p:
  - Python2 では日本語を含む文字列は .encode('utf-8')して UTF-8 で保持。
- p:
  - Python3 では日本語の有無に関係なく、素直にstrのままでよし。

- h3: 日本語を含むUTF-8のテキストを標準入力、標準出力で扱いたい
- p:
  - Python2 では素直に sys.stdin/sys.stdout を read/write。
- p:
  - Python3 では sys.stdin.buffer , sys.stdout.buffer を使う。
- p:
  - Python2 の世界には .buffer は存在しないので注意。

あとはスクリプトなり何なりで、例えば

$ ( echo '<html><head>' ; ./ezhtml.py y < foo_head.yaml ; echo '</head><body>' ; ./ezhtml.py  y < foo_body.yaml ; echo '</body></html>' ) | nkf -j > foo2.html

$ nkf -g foo2.html
ISO-2022-JP

$ nkf -u foo2.html
<html><head>
<meta http-equiv="Content-Type" content="text/html;charset=iso-2022-jp">
<title>py23str</title>
<style>pre{ background: lightgray; }</style>
<style>img{ max-width: 100%; height: auto; }</style>
<style>h3{ border-left: solid gray; padding: 1em 0.5em; }</style>
</head><body>
<h1>Python2とPython3での日本語文字列対応について</h1>
<p>毎回、同じようにつまづいて、同じような感じで対応してます。</p>
<p>なので、いいかげん自分に判りやすいようにまとめておきます。</p>
<p>日本語対応といっても、ソースコード中に日本語を書くつもりはありません。</p>
<p>データはYAML形式のファイルで用意。</p>
<p>そして、YAML形式データファイル中の文字列を、UTF-8で日本語に置き換えようとして、
毎回「うぅっ」とうなってます。</p>
<h2>結論</h2>
<h3>日本語を含む文字列処理で .foramt() や .join() を使いたい</h3>
<p>Python2 では日本語を含む文字列は .encode('utf-8')して UTF-8 で保持。</p>
<p>Python3 では日本語の有無に関係なく、素直にstrのままでよし。</p>
<h3>日本語を含むUTF-8のテキストを標準入力、標準出力で扱いたい</h3>
<p>Python2 では素直に sys.stdin/sys.stdout を read/write。</p>
<p>Python3 では sys.stdin.buffer , sys.stdout.buffer を使う。</p>
<p>Python2 の世界には .buffer は存在しないので注意。</p>
</body></html>

foo2.html

となります。


タグ

おれおれ仕様のツールなので、 自分がよく使うHTMLのタグだけ対応して、 滅多に使わないものは、最後に手動で編集する事にします。

HTMLのbodyの中で、自分がよく使うタグは何か?

とりあえず、このくらい。

最初はここから foo.txt の範囲だけに絞って

だけで骨組みを考えてみます。


簡易にモード切り替えで

foo.txt から foo_body.yaml を生成したい訳ですが、 テキストを、属してるタグで切り分けてみると

;;; --> h1
Python2とPython3での日本語文字列対応について
;;; <-- h1

;;; --> p
  毎回、同じようにつまづいて、同じような感じで対応してます。
  なので、いいかげん自分に判りやすいようにまとめておきます。
  日本語対応といっても、ソースコード中に日本語を書くつもりはありません。
  データはYAML形式のファイルで用意。
  そして、YAML形式データファイル中の文字列を、UTF-8で日本語に置き換えようとして、
  毎回「うぅっ」とうなってます。
;;; <-- p

;;; --> h2
結論
;;; <-- h2

;;; --> h3
  日本語を含む文字列処理で .foramt() や .join() を使いたい
;;; <-- h3

;;; --> p
    Python2 では日本語を含む文字列は .encode('utf-8')して UTF-8 で保持。
    Python3 では日本語の有無に関係なく、素直にstrのままでよし。
;;; <-- p

;;; --> h3
  日本語を含むUTF-8のテキストを標準入力、標準出力で扱いたい
;;; <-- h3

;;; --> p
    Python2 では素直に sys.stdin/sys.stdout を read/write。
    Python3 では sys.stdin.buffer , sys.stdout.buffer を使う。
    Python2 の世界には .buffer は存在しないので注意。
;;; <-- p

HTML形式だと、開始タグと終了タグで、まさにこのような感じで領域を指示します。

おれおれマークダウンでは、簡易な記述を目指すので、モード(状態)を持たせます。

テキストの先頭から末尾に向かって、状態を切り替えて、どのタグの領域かを指示する事にします。

例えば、次のように。

h1
Python2とPython3での日本語文字列対応について

p
  毎回、同じようにつまづいて、同じような感じで対応してます。

  なので、いいかげん自分に判りやすいようにまとめておきます。

  日本語対応といっても、ソースコード中に日本語を書くつもりはありません。

  データはYAML形式のファイルで用意。

  そして、YAML形式データファイル中の文字列を、UTF-8で日本語に置き換えようとして、
  毎回「うぅっ」とうなってます。

h2
結論

h3
  日本語を含む文字列処理で .foramt() や .join() を使いたい

p
    Python2 では日本語を含む文字列は .encode('utf-8')して UTF-8 で保持。

    Python3 では日本語の有無に関係なく、素直にstrのままでよし。

h3
  日本語を含むUTF-8のテキストを標準入力、標準出力で扱いたい

p
    Python2 では素直に sys.stdin/sys.stdout を read/write。

    Python3 では sys.stdin.buffer , sys.stdout.buffer を使う。

    Python2 の世界には .buffer は存在しないので注意。

p, h1, h2, h3をモード名として、モード名だけの行が現れると、 現在のモードをそのモードに切り替えます。

h1, h2, h3モード

他のモードに切り替わるまでの間の複数行のテキストについて

h1
Python2とPython3での日本語文字列対応について

p

- h1: Python2とPython3での日本語文字列対応について

てな具合に。

pモード

他のモードに切り替わるまでの間の複数行のテキストについて

p
  毎回、同じようにつまづいて、同じような感じで対応してます。

  なので、いいかげん自分に判りやすいようにまとめておきます。

  日本語対応といっても、ソースコード中に日本語を書くつもりはありません。

  データはYAML形式のファイルで用意。

  そして、YAML形式データファイル中の文字列を、UTF-8で日本語に置き換えようとして、
  毎回「うぅっ」とうなってます。

h2

- p:
  - 毎回、同じようにつまづいて、同じような感じで対応してます。
- p:
  - なので、いいかげん自分に判りやすいようにまとめておきます。
- p:
  - 日本語対応といっても、ソースコード中に日本語を書くつもりはありません。
- p:
  - データはYAML形式のファイルで用意。
- p:
  - そして、YAML形式データファイル中の文字列を、UTF-8で日本語に置き換えようとして、
  - 毎回「うぅっ」とうなってます。

てな具合に。


バージョン1 (h,pタグ)

ではこの仕様で、骨組みのコーディング。

ezmd.py

$ cat ezmd.py
#!/usr/bin/env python

import yaml
import nkf

heads = [ 'h1', 'h2', 'h3', 'h4', 'h5', 'h6', 'h7', 'h8', 'h9' ]
end = '$$$_end_$$$'
modes = heads + [ 'p', end ]

def do_mode(mode, buf, res):
        if mode in heads:
                buf = list( map( lambda s: s.strip(), buf ) )
                buf = list( filter( lambda s: s!='', buf ) )
                s = ''.join(buf)
                res.append( { mode: s } )
        elif mode == 'p':
                buf = list( map( lambda s: s.strip(), buf ) )

                buf.append('')
                (lsts, lst) = ( [], [] )
                for s in buf:
                        if s:
                                lst.append(s)
                        elif lst:
                                lsts.append(lst)
                                lst = []
                for lst in lsts:
                        res.append( { 'p': lst } )
def ezmd(lst):
        lst = ['p'] + lst + [end]
        (buf, res) = ( [], [] )
        mode = ''
        while mode != end:
                s = lst.pop(0)
                if s in modes and s != mode:
                        do_mode(mode, buf, res)
                        mode = s
                        buf = []
                else:
                        buf.append(s)
        return res

if __name__ == "__main__":
        b = nkf.get_stdin()
        (s, nkf_opt) = nkf.to_str(b)
        lst = s.split('\n')

        lst = ezmd(lst)

        u8 = yaml.dump( lst, default_flow_style=False, allow_unicode=True, encoding='utf-8' )
        b = nkf.cvt(u8, nkf_opt) if nkf_opt != '-u' else u8
        nkf.put_stdout(b)
# EOF

日本語の文字コードの問題やPython2, Python3の問題は、すべて nkf.py が吸収してくれてるはずと信じて、進めまてみます。

簡易なHTMLパーサ 2018秋 から

ezhtml.py

nkf.py は使いまわしつつ、互換性を保ちながらアップデートしてきたので、 テキスト配置ツール から最新版の

nkf.py

を配置しておきます。

おれおれ仕様のテキストファイルは

foo2.txt

$ cat foo2.txt
h1
Python2とPython3での日本語文字列対応について

p
  毎回、同じようにつまづいて、同じような感じで対応してます。

  なので、いいかげん自分に判りやすいようにまとめておきます。

  日本語対応といっても、ソースコード中に日本語を書くつもりはありません。

  データはYAML形式のファイルで用意。

  そして、YAML形式データファイル中の文字列を、UTF-8で日本語に置き換えようとして、
  毎回「うぅっ」とうなってます。

h2
結論

h3
  日本語を含む文字列処理で .foramt() や .join() を使いたい

p
    Python2 では日本語を含む文字列は .encode('utf-8')して UTF-8 で保持。

    Python3 では日本語の有無に関係なく、素直にstrのままでよし。

h3
  日本語を含むUTF-8のテキストを標準入力、標準出力で扱いたい

p
    Python2 では素直に sys.stdin/sys.stdout を read/write。

    Python3 では sys.stdin.buffer , sys.stdout.buffer を使う。

    Python2 の世界には .buffer は存在しないので注意。

それでは実行。

$ ./ezmd.py < foo2.txt
- h1: Python2とPython3での日本語文字列対応について
- p:
  - 毎回、同じようにつまづいて、同じような感じで対応してます。
- p:
  - なので、いいかげん自分に判りやすいようにまとめておきます。
- p:
  - 日本語対応といっても、ソースコード中に日本語を書くつもりはありません。
- p:
  - データはYAML形式のファイルで用意。
- p:
  - そして、YAML形式データファイル中の文字列を、UTF-8で日本語に置き換えようとして、
  - 毎回「うぅっ」とうなってます。
- h2: 結論
- h3: 日本語を含む文字列処理で .foramt() や .join() を使いたい
- p:
  - Python2 では日本語を含む文字列は .encode('utf-8')して UTF-8 で保持。
- p:
  - Python3 では日本語の有無に関係なく、素直にstrのままでよし。
- h3: 日本語を含むUTF-8のテキストを標準入力、標準出力で扱いたい
- p:
  - Python2 では素直に sys.stdin/sys.stdout を read/write。
- p:
  - Python3 では sys.stdin.buffer , sys.stdout.buffer を使う。
- p:
  - Python2 の世界には .buffer は存在しないので注意。

出力されたHTML形式をさらにezhtml.pyにつないでHTML形式に。

$ ./ezmd.py < foo2.txt | ./ezhtml.py
<h1>Python2とPython3での日本語文字列対応について</h1>
<p>毎回、同じようにつまづいて、同じような感じで対応してます。</p>
<p>なので、いいかげん自分に判りやすいようにまとめておきます。</p>
<p>日本語対応といっても、ソースコード中に日本語を書くつもりはありません。</p>
<p>データはYAML形式のファイルで用意。</p>
<p>そして、YAML形式データファイル中の文字列を、UTF-8で日本語に置き換えようとして、
毎回「うぅっ」とうなってます。</p>
<h2>結論</h2>
<h3>日本語を含む文字列処理で .foramt() や .join() を使いたい</h3>
<p>Python2 では日本語を含む文字列は .encode('utf-8')して UTF-8 で保持。</p>
<p>Python3 では日本語の有無に関係なく、素直にstrのままでよし。</p>
<h3>日本語を含むUTF-8のテキストを標準入力、標準出力で扱いたい</h3>
<p>Python2 では素直に sys.stdin/sys.stdout を read/write。</p>
<p>Python3 では sys.stdin.buffer , sys.stdout.buffer を使う。</p>
<p>Python2 の世界には .buffer は存在しないので注意。</p>

大丈夫そうですね。 headとつなげて仕上げを。

仕上げ用のツールを用意しときます。

to_html.py

$ cat to_html.py
#!/usr/bin/env python

import sys
import subprocess

if __name__ == "__main__":
        if len(sys.argv) < 3:
                print( 'Usage: {} head.yaml body.txt'.format( sys.argv[0] ) )
                sys.exit(1)

        cmd = "( echo '<html><head>' ; ./ezhtml.py y < {} ; echo '</head><body>' ; ./ezmd.py < {} | ./ezhtml.py y ; echo '</body></html>' ) | nkf -j";
        cmd = cmd.format( sys.argv[1], sys.argv[2] )
        subprocess.call(cmd, shell=True)
# EOF

$ ./to_html.py foo_head.yaml foo2.txt > foo3.html

$ nkf -g foo3.html
ISO-2022-JP

foo3.html

OK。

todo


バージョン2 (preタグ)

追加してみます。

preモード

preタグの場合、どこまでがpreタグの中か? 次のモードへの切り替えの判定が微妙です。

このモードは特別に、'/'だけの行でモード終了としてみます。

行頭に'/'だけ表示したい事はまぁ無いだろうし、 あったとしても、' ' + '/' にして行頭にスペースを入れてしのぐ事にします。

モードが終了するまでの間の複数行のテキストについて

preタグのYAMLへの変換は

簡易なHTMLパーサ 2018秋 preタグのyamlダンプ でこしらえた yaml_dump() を流用しておきます。

ezhtml.pyのオリジナルのyaml_dump()ではstrを返す仕様にしてました。 今回の場面ではUTF-8のままで良いので、そのように修正して使います。

モード終了指示の方式にすると、 '/' で終了してから、次のモードまでの滞空期間ができてしまいます。

モードが何者でもないその間は、とりあえずデフォルトのpモードで。

pモード中に何もテキストがなく、続く別のモードが始まれば、 デフォルトpモードでは何も表示しないので、大丈夫でしょう。

v2.patch

$ cat v2.patch | patch -p1

foo_2.txt

$ cat foo_2.txt
h1
Python2とPython3での日本語文字列対応について

p
  毎回、同じようにつまづいて、同じような感じで対応してます。

  なので、いいかげん自分に判りやすいようにまとめておきます。

  日本語対応といっても、ソースコード中に日本語を書くつもりはありません。

  データはYAML形式のファイルで用意。

  そして、YAML形式データファイル中の文字列を、UTF-8で日本語に置き換えようとして、
  毎回「うぅっ」とうなってます。

h2
結論

h3
  日本語を含む文字列処理で .foramt() や .join() を使いたい

p
    Python2 では日本語を含む文字列は .encode('utf-8')して UTF-8 で保持。

    Python3 では日本語の有無に関係なく、素直にstrのままでよし。

h3
  日本語を含むUTF-8のテキストを標準入力、標準出力で扱いたい

p
    Python2 では素直に sys.stdin/sys.stdout を read/write。

    Python3 では sys.stdin.buffer , sys.stdout.buffer を使う。

    Python2 の世界には .buffer は存在しないので注意。

pre
$ cat p2.py
#!/usr/bin/env python2

import sys
import yaml

if __name__ == "__main__":
        s = sys.stdin.read()
        d = yaml.load(s)
        foo = d.get('foo')
        bar = d.get('bar')
        d['hoge'] = foo + ' ' + bar
        d['fuga'] = 'foo={} bar={}'.format(foo, bar)
        d['guha'] = '(^_^)'.join( d.values() )
        s = yaml.dump(d, default_flow_style=False)
        sys.stdout.write(s)
# EOF
/

ここはデフォルトp

p
ここは明示的にp

pre
ここはpre
p
  ここもpre
h1
  ここもpre
/
p
  ここはp

実行してみます。

$ ./ezmd.py < foo_2.txt
- h1: Python2とPython3での日本語文字列対応について
- p:
  - 毎回、同じようにつまづいて、同じような感じで対応してます。
- p:
  - なので、いいかげん自分に判りやすいようにまとめておきます。
- p:
  - 日本語対応といっても、ソースコード中に日本語を書くつもりはありません。
- p:
  - データはYAML形式のファイルで用意。
- p:
  - そして、YAML形式データファイル中の文字列を、UTF-8で日本語に置き換えようとして、
  - 毎回「うぅっ」とうなってます。
- h2: 結論
- h3: 日本語を含む文字列処理で .foramt() や .join() を使いたい
- p:
  - Python2 では日本語を含む文字列は .encode('utf-8')して UTF-8 で保持。
- p:
  - Python3 では日本語の有無に関係なく、素直にstrのままでよし。
- h3: 日本語を含むUTF-8のテキストを標準入力、標準出力で扱いたい
- p:
  - Python2 では素直に sys.stdin/sys.stdout を read/write。
- p:
  - Python3 では sys.stdin.buffer , sys.stdout.buffer を使う。
- p:
  - Python2 の世界には .buffer は存在しないので注意。
- pre: |
    $ cat p2.py
    #!/usr/bin/env python2

    import sys
    import yaml

    if __name__ == "__main__":
            s = sys.stdin.read()
            d = yaml.load(s)
            foo = d.get('foo')
            bar = d.get('bar')
            d['hoge'] = foo + ' ' + bar
            d['fuga'] = 'foo={} bar={}'.format(foo, bar)
            d['guha'] = '(^_^)'.join( d.values() )
            s = yaml.dump(d, default_flow_style=False)
            sys.stdout.write(s)
    # EOF
- p:
  - ここはデフォルトp
- p:
  - ここは明示的にp
- pre: |
    ここはpre
    p
      ここもpre
    h1
      ここもpre
- p:
  - ここはp

大丈夫そうですね。

$ ./to_html.py foo_head.yaml foo_2.txt > foo_2.html

foo_2.html

todo


バージョン3 (ul,liタグ)

追加してみます。

ulモード

全体の簡単にするためにモードの開始、終了をトップレベルの状態の遷移だけにしました。

なので、基本的に「入れ子」の構造を諦めてます。

が、ですが、このulモードの中だけは「入れ子」を結構使ってます。

例えば

- ul:
  - li /: 標準入力からYAML形式のテキストを読み込み
  - li /: yaml.load()でテキストをデータに
  - li /: データの文字列2つを
  - li /: ごにょごにょいじって
  - ul:
    - li /: foo + ' ' + bar
    - li /: .format()
    - li /: .join()
  - li /: yaml.dump()でデータをYAML形式のテキストにして
  - li /: 標準出力に書き出し

こうして

<ul><li>標準入力からYAML形式のテキストを読み込み
<li>yaml.load()でテキストをデータに
<li>データの文字列2つを
<li>ごにょごにょいじって
<ul><li>foo + ' ' + bar
<li>.format()
<li>.join()</ul>
<li>yaml.dump()でデータをYAML形式のテキストにして
<li>標準出力に書き出し</ul>

こうなって

このように。

ここまでのモードの関連に従うならば、 例えば上記の結果になる元のテキストは

ul
  標準入力からYAML形式のテキストを読み込み
  yaml.load()でテキストをデータに
  データの文字列2つを
  ごにょごにょいじって
    foo + ' ' + bar
    .format()
    .join()
  yaml.dump()でデータを \
  YAML形式のテキストにして
  標準出力に書き出し

こうありたい。

ulモード中では、行頭の字下げの数で「入れ子」の指示になるという仕様で、 何とか考えてみました。

v3.patch

$ cat v3.patch | patch -p1

foo_3.txt

$ cat foo_3.txt
  :
p
  ここはp

ul
  標準入力からYAML形式のテキストを読み込み
  yaml.load()でテキストをデータに
  データの文字列2つを
  ごにょごにょいじって
    foo + ' ' + bar
    .format()
    .join()
  yaml.dump()でデータを \
  YAML形式のテキストにして
  標準出力に書き出し

pre
  ここはpre

実行してみます。

$ ./ezmd.py < foo_3.txt
  :
- p:
  - ここはp
- ul:
  - li /: 標準入力からYAML形式のテキストを読み込み
  - li /: yaml.load()でテキストをデータに
  - li /: データの文字列2つを
  - li /: ごにょごにょいじって
  - ul:
    - li /: foo + ' ' + bar
    - li /: .format()
    - li /: .join()
  - li /: yaml.dump()でデータをYAML形式のテキストにして
  - li /: 標準出力に書き出し
- pre: |2
      ここはpre

大丈夫そうですね。

$ ./to_html.py foo_head.yaml foo_3.txt > foo_3.html

foo_3.html

todo


バージョン4 (a (href)タグ)

追加してみます。

自分のa href="xxx"タグの使い方を振り返ると、 ほとんどpタグの中かulタグの中です。

なのでとりあえず、pモードとulモードの文字列処理の箇所だけに、対応を入れてみます。

a (href)の場合、トップレベルのモードを遷移させるまでもなさそうです。

文字列中に [[ xxx | yyy ]] の記載があれば
  YAML形式の - a href="xxx": yyy を経て
  HTML形式で <a href="xxx"> yyy </a> に
文字列中に [[ xxx ]] の記載があれば
  YAML形式の - a href="xxx": xxx } を経て
  HTML形式で <a href="xxx"> xxx </a> に

このくらいの仕様でやってみます。

v4.patch

$ cat v4.patch | patch -p1

foo_4.txt

$ cat foo_4.txt
  :
p
ここは明示的にp

  [[v2.patch]]

バージョン2のための[[ v2.patch | パッチ ]] となります。

[[http://kondoh.html.xdomain.jp/ezhtml/index.html | 簡易なHTMLパーサ 2018秋]]

これは[[http://kondoh.html.xdomain.jp/p3d/index.html#v3_import | pythonのモジュールのインポート]]について。

pre
ここはpre
p
  ここもpre
h1
  ここもpre
/

ul
[[v2.patch]]
[[v3.patch]]
バージョン2のための[[ v2.patch | パッチ ]] となります。
これは[[http://kondoh.html.xdomain.jp/p3d/index.html#v3_import | pythonのモジュールのインポート]]について。

p
  ここはp
  :

実行してみます。

$ ./ezmd.py < foo_4.txt
  :

- p:
  - ここは明示的にp
- p:
  - a href="v2.patch": v2.patch
- p:
  - バージョン2のための
  - a href="v2.patch": パッチ
  - となります。
- p:
  - a href="http://kondoh.html.xdomain.jp/ezhtml/index.html": 簡易なHTMLパーサ 2018秋
- p:
  - これは
  - a href="http://kondoh.html.xdomain.jp/p3d/index.html#v3_import": pythonのモジュールのインポート
  - について。
- pre: |
    ここはpre
    p
      ここもpre
    h1
      ここもpre
- ul:
  - li /:
      a href="v2.patch": v2.patch
  - li /:
      a href="v3.patch": v3.patch
  - li /:
    - バージョン2のための
    - a href="v2.patch": パッチ
    - となります。
  - li /:
    - これは
    - a href="http://kondoh.html.xdomain.jp/p3d/index.html#v3_import": pythonのモジュールのインポート
    - について。
- p:
  - ここはp

大丈夫そうですね。

$ ./to_html.py foo_head.yaml foo_4.txt > foo_4.html

foo_4.html

todo


バージョン5 (hrタグ)

追加してみます。

複数のハイフンだけの行が現れると、横線に変換する事にしてみます。

ハイフン2つだけとかなら他に何か意味ありそうなので、 一応4個以上の場合に有効とします。

自分のhrタグの使用箇所は、そのほとんどが

- p: { hr: / }

経ての

<p><hr></p>

として使ってます。

ハイフン4個以上の行が複数行続く場合も、その行数の横線になるように。

横線指示の直後にモード指定が無い場合は、 デフォルトのモード'p'として扱う事にします。

v5.patch

$ cat v5.patch | patch -p1

foo_5.txt

$ cat foo_5.txt
  :
  毎回「うぅっ」とうなってます。

----

h2
結論
  :
    Python2 の世界には .buffer は存在しないので注意。

----

pre
$ cat p2.py
#!/usr/bin/env python2
  :

p
  ここはp

---
----

----

ここは暗黙のp

h3
  ここはh3

---
----
----
---

p
  ここはp

ul
  標準入力からYAML形式のテキストを読み込み
  :

実行してみます。

$ ./ezmd.py < foo_5.txt
  :
  - 毎回「うぅっ」とうなってます。
- p:
    hr: /
- h2: 結論
  :
- p:
  - Python2 の世界には .buffer は存在しないので注意。
- p:
    hr: /
- pre: |
    $ cat p2.py
    #!/usr/bin/env python2
  :
- p:
  - ここはp
- p:
  - '---'
- p:
    hr: /
- p:
    hr: /
- p:
  - ここは暗黙のp
- h3: ここはh3---
- p:
    hr: /
- p:
    hr: /
- p:
  - '---'
- p:
  - ここはp
- ul:
  - li /: 標準入力からYAML形式のテキストを読み込み
  :

大丈夫そうですね。

$ ./to_html.py foo_head.yaml foo_5.txt > foo_5.html

foo_5.html

todo


バージョン6 (img,videoタグ)

追加してみます。

img, video ともに自分で使うときのパターンはほぼお決まりで、 a (href)タグと似たようなものです。

なので仕様もa (href)タグと同じような感じにします。

a (href)タグ同様に、pモードとulモードの文字列処理の箇所だけに、対応を入れます。

文字列中に [[ img | xxx ]] の記載があれば
  YAML形式の - img srcf="xxx": / を経て
  HTML形式で <img src="xxx"> に
文字列中に [[ video | xxx ]] の記載があれば
  YAML形式の - video src="xxx" controls playsinline: "" を経て
  HTML形式で <video src="xxx" controls playsinline></video> に

形式をa (href)タグの場合と合わせたので、 a (href)タグの箇所をちょっと改造するだけの対応になります。

v6.patch

$ cat v6.patch | patch -p1

foo_6.txt

$ cat foo_6.txt
  :
p
    Python2 では素直に sys.stdin/sys.stdout を read/write。

    Python3 では sys.stdin.buffer , sys.stdout.buffer を使う。

    Python2 の世界には .buffer は存在しないので [[img|beat.jpg]] 注意。
  :
ul
[[v2.patch]]
[[v3.patch]]
バージョン2のための[[ v2.patch | パッチ ]] となります。
これは[[http://kondoh.html.xdomain.jp/p3d/index.html#v3_import | pythonのモジュールのインポート]]について。
[[ img | beat.jpg ]]
[[ video | cut.mp4 ]]

p
  ここはp
  :
p
  ここはp

[[video|http://kondoh2.html.xdomain.jp/rt/out_v44/fix_1.mp4]]

ul
  標準入力からYAML形式のテキストを読み込み
  :

実行してみます。

$ ./ezmd.py < foo_6.txt
  :
- p:
  - Python2 では日本語を含む文字列は .encode('utf-8')して UTF-8 で保持。
- p:
  - Python3 では日本語の有無に関係なく、素直にstrのままでよし。
- h3: 日本語を含むUTF-8のテキストを標準入力、標準出力で扱いたい
- p:
  - Python2 では素直に sys.stdin/sys.stdout を read/write。
- p:
  - Python3 では sys.stdin.buffer , sys.stdout.buffer を使う。
- p:
  - Python2 の世界には .buffer は存在しないので
  - img src="beat.jpg": /
  - 注意。
  :
- ul:
  - li /:
      a href="v2.patch": v2.patch
  - li /:
      a href="v3.patch": v3.patch
  - li /:
    - バージョン2のための
    - a href="v2.patch": パッチ
    - となります。
  - li /:
    - これは
    - a href="http://kondoh.html.xdomain.jp/p3d/index.html#v3_import": pythonのモジュールのインポート
    - について。
  - li /:
      img src="beat.jpg": /
  - li /:
      video src="cut.mp4" controls playsinline: ''
- p:
  - ここはp
  :
- p:
  - ここはp
- p:
  - video src="http://kondoh2.html.xdomain.jp/rt/out_v44/fix_1.mp4" controls playsinline: ''
- ul:
  - li /: 標準入力からYAML形式のテキストを読み込み

大丈夫そうですね。

$ ./to_html.py foo_head.yaml foo_6.txt > foo_6.html

foo_6.html

todo


バージョン7 (sタグ)

追加してみます。

sタグは「打ち消し線」の指定です。

これまた a (href)タグ同様に、pモードとulモードの文字列処理の箇所だけの対応で。

形式も強引にa (href)タグに合わせてしまいます。(^_^;

文字列中に [[ - | xxx ]] の記載があれば
  YAML形式の - s: xxx を経て
  HTML形式で <s> xxx </s> に

形式を強引にもa (href)タグの場合と合わせたので、 変更箇所は驚くほど軽微です。

v7.patch

$ cat v7.patch | patch -p1

foo_7.txt

$ cat foo_7.txt
  :
  そして、YAML形式データファイル中の文字列を、UTF-8で日本語に置き換えようとして、
  毎回[[ - |「うぅっ」]] 「ぬはぁ」とうなってます。

----
  :
ul
  標準入力からYAML形式のテキストを読み込み
  yaml.load()でテキストをデータに
  [[-|データの文字列2つを]]
  ごにょごにょいじって
  :

実行してみます。

$ ./ezmd.py < foo_7.txt
  :
- p:
  - そして、YAML形式データファイル中の文字列を、UTF-8で日本語に置き換えようとして、
  - 毎回
  - s: 「うぅっ」
  - 「ぬはぁ」とうなってます。
- p:
    hr: /
  :
- ul:
  - li /: 標準入力からYAML形式のテキストを読み込み
  - li /: yaml.load()でテキストをデータに
  - li /:
      s: データの文字列2つを
  - li /: ごにょごにょいじって
  :

大丈夫そうですね。

$ ./to_html.py foo_head.yaml foo_7.txt > foo_7.html

foo_7.html

todo


バージョン8 目次機能

目次を自動生成する機能を追加してみます。

さすがにこの機能は2 passになります。

'index'だけの行が現れると目次モード。

そこから他のモードになるまでの区間に目次を挿入します。

目次モード中の箇所に、目次作成のためのパラメータを指定します。

index
  パラメータ

パラメータは、目次にするヘッダタグの種別の範囲を指定します。

範囲指定はPythonのリストのスライスの指定のようにします。

index
  2:5

lst[2:5] なので目次にする対象は h2, h3, h4

index
  3:

lst[3:] なので、目次にする対象は h3, h4, ....

index
  :3

lst[:3] なので、目次にする対象は h1, h2

index

パラメータの指定がなければ lst[:] 扱いで、全てのヘッダタグを対象にします。

目次の形式は、ヘッダタグの階層に従って ulタグの入れ子の構成にします。

ulタグの処理は既に実装してるので、 ヘッダの番号に応じて字下げしたテキストデータを作り、 ulタグとして処理すれば楽チンですね。

v8.patch

$ cat v8.patch | patch -p1

foo_8.txt

$ cat foo_8.txt
  :
  そして、YAML形式データファイル中の文字列を、UTF-8で日本語に置き換えようとして、
  毎回[[ - |「うぅっ」]] 「ぬはぁ」とうなってます。

----
index
----
p
  2: の場合
index
  2:
----
p
  :4 の場合
index
  :4
----
p
  2:3 の場合
index
  2:3
----
p
  2 の場合
index
  2
----
p
  3 の場合
index
  3
----

h2
結論

実行してみます。

$ ./ezmd.py < foo_8.txt
  :
- p:
  - そして、YAML形式データファイル中の文字列を、UTF-8で日本語に置き換えようとして、
  - 毎回
  - s: 「うぅっ」
  - 「ぬはぁ」とうなってます。
- p:
    hr: /
- ul:
  - li /:
      a href="#c_1_0": Python2とPython3での日本語文字列対応について
  - ul:
    - li /:
        a href="#c_2_1": 結論
    - ul:
      - li /:
          a href="#c_3_2": 日本語を含む文字列処理で .foramt() や .join() を使いたい
      - li /:
          a href="#c_3_3": 日本語を含むUTF-8のテキストを標準入力、標準出力で扱いたい
      - li /:
          a href="#c_3_4": ここはh3---
- p:
    hr: /
- p:
  - '2: の場合'
- ul:
  - li /:
      a href="#c_2_1": 結論
  - ul:
    - li /:
        a href="#c_3_2": 日本語を含む文字列処理で .foramt() や .join() を使いたい
    - li /:
        a href="#c_3_3": 日本語を含むUTF-8のテキストを標準入力、標準出力で扱いたい
    - li /:
        a href="#c_3_4": ここはh3---
- p:
    hr: /
- p:
  - :4 の場合
- ul:
  - li /:
      a href="#c_1_0": Python2とPython3での日本語文字列対応について
  - ul:
    - li /:
        a href="#c_2_1": 結論
    - ul:
      - li /:
          a href="#c_3_2": 日本語を含む文字列処理で .foramt() や .join() を使いたい
      - li /:
          a href="#c_3_3": 日本語を含むUTF-8のテキストを標準入力、標準出力で扱いたい
      - li /:
          a href="#c_3_4": ここはh3---
- p:
    hr: /
- p:
  - 2:3 の場合
- ul:
  - li /:
      a href="#c_2_1": 結論
- p:
    hr: /
- p:
  - 2 の場合
- ul:
  - li /:
      a href="#c_2_1": 結論
- p:
    hr: /
- p:
  - 3 の場合
- ul:
  - li /:
      a href="#c_3_2": 日本語を含む文字列処理で .foramt() や .join() を使いたい
  - li /:
      a href="#c_3_3": 日本語を含むUTF-8のテキストを標準入力、標準出力で扱いたい
  - li /:
      a href="#c_3_4": ここはh3---
- p:
    hr: /
- h2:
    a name="c_2_1": 結論

さすがにこれは、パッとみて大丈夫かどうか分かりかねますね。

$ ./to_html.py foo_head.yaml foo_8.txt | tee foo_8.html | nkf -u
  :
<p>そして、YAML形式データファイル中の文字列を、UTF-8で日本語に置き換えようとして、
毎回
<s>「うぅっ」</s>
「ぬはぁ」とうなってます。</p>
<p><hr></p>
<ul><li><a href="#c_1_0">Python2とPython3での日本語文字列対応について</a>
<ul><li><a href="#c_2_1">結論</a>
<ul><li><a href="#c_3_2">日本語を含む文字列処理で .foramt() や .join() を使いたい</a>
<li><a href="#c_3_3">日本語を含むUTF-8のテキストを標準入力、標準出力で扱いたい</a>
<li><a href="#c_3_4">ここはh3---</a></ul></ul></ul>
<p><hr></p>
<p>2: の場合</p>
<ul><li><a href="#c_2_1">結論</a>
<ul><li><a href="#c_3_2">日本語を含む文字列処理で .foramt() や .join() を使いたい</a>
<li><a href="#c_3_3">日本語を含むUTF-8のテキストを標準入力、標準出力で扱いたい</a>
<li><a href="#c_3_4">ここはh3---</a></ul></ul>
<p><hr></p>
<p>:4 の場合</p>
<ul><li><a href="#c_1_0">Python2とPython3での日本語文字列対応について</a>
<ul><li><a href="#c_2_1">結論</a>
<ul><li><a href="#c_3_2">日本語を含む文字列処理で .foramt() や .join() を使いたい</a>
<li><a href="#c_3_3">日本語を含むUTF-8のテキストを標準入力、標準出力で扱いたい</a>
<li><a href="#c_3_4">ここはh3---</a></ul></ul></ul>
<p><hr></p>
<p>2:3 の場合</p>
<ul><li><a href="#c_2_1">結論</a></ul>
<p><hr></p>
<p>2 の場合</p>
<ul><li><a href="#c_2_1">結論</a></ul>
<p><hr></p>
<p>3 の場合</p>
<ul><li><a href="#c_3_2">日本語を含む文字列処理で .foramt() や .join() を使いたい</a>
<li><a href="#c_3_3">日本語を含むUTF-8のテキストを標準入力、標準出力で扱いたい</a>
<li><a href="#c_3_4">ここはh3---</a></ul>
<p><hr></p>
<h2><a name="c_2_1">結論</a></h2>
  :

むー、まぁ、百聞は一見にしかず

foo_8.html

大丈夫そうですね。

todo


バージョン9 headタグのtitleを何とかする

自分ではいつもheadタグには日本語は書かないので、 ここは安易に

v9.patch

$ cat v9.patch | patch -p1

実行してみます。

$ ./to_html.py
Usage: ./to_html.py head.yaml body.txt [title]

$ ./to_html.py foo_head.yaml foo_8.txt | grep title
<title>py23str</title>

$ ./to_html.py foo_head.yaml foo_8.txt 'sample page' | grep title
<title>sample page</title>

$ ./to_html.py foo_head.yaml foo_8.txt 'sample page' > foo_9.html

OK

foo_9.html

todo


バージョン10 バグ修正や調整など

まずは不具合の修正

色々試してみて不具合でました。

ulタグの処理前に、字下げの絡みで行の結合をする箇所。

def esc_join(lst):
	res = []
	for s in lst:
		if res and res[-1] and res[-1][-1] == '\\':
			t = res[-1][:-1]
			res[-1] = strip_tail(t) + strip_head(s)
		else:
			res.append(s)
	return res

res[-1]が空文字列''の場合に、''[-1]になってアクセスでエラーが出る事がありました。

-       if res and res[-1][-1] == '\\':
+       if res and res[-1] and res[-1][-1] == '\\':

な修正をしておきます。

調整

次の調整を入れておきます。

v10.patch

$ cat v10.patch | patch -p1

お試し

では満を持して、このページ自身もこの仕様のテキストで書いてみましょう。

head.yaml

index.ez.txt

このテキストファイルから

$ ./to_html.py head.yaml index.ez.txt ezmd > index.html

index.html

となります。

(再帰だ〜)

todo