2021/FEB/23
更新履歴
日付
変更内容 2018秋
新規作成 2018/SEP/17
漢字
入力データのHTML自動判定
HTMLからYAMLへの変換2018/SEP/18
preタグのyamlダンプ
liタグの改行の辺りを
fileコマンドの判定の甘さ対策
大きいデータの標準入力への書き込み対応2018/SEP/20
preタグの中のタグの改行対応
タグ中のタグの中身はstirp()かけない対応
コメント対応2020/FEB/01
kon_ut対応 2021/FEB/23
bare対応
自分のページのHTMLは、簡素で限られたHTMLタグしか使われてません。
なぜか?
HTMLを手打ちしてるからです。
別に凝ったことはしないので「まぁこれでいいか」と。
にしても、HTMLのタグのタイプにボチボチ疲れてきました。
後でちょっと手を加えたいときなど、今どこにいるのか、ちょいちょい迷子になることしばしば。
どうせ自分で使う分には、限られたパターンしか使ってないし、 HTML形式を簡単にYAML形式に変換できないものか?
HTMLからYAMLに変換して、編集して、またYAMLからHTMLに戻せれないものか?
という事でpythonでツールを作ってみます。
HTMLのタグと文字列をYAML形式でどう表現すべしか?
私の中では「YAML形式」イコール「pythonの辞書とリストと文字列」
pythonのオブジェクトとしてどう保持したら良いか?
辞書は便利そうですが順番が保証されません。 かと言ってリストだけでは、ネスとが深くなると訳が分からなくなりそうです。
方針
これくらいで行けそうかな?
「/」という一文字の文字列を特別な値として使うので、 例えば <p>/</p> を読み込んだとすると、 終了タグがない <p>/ の扱いになりますね。
まぁ自分でそんなパターンを使う事は滅多にないだろうし、 後でもし困ったら何とかすれば良いでしょ。
例えば
ck1.html
<html>
<head>
<title>Title</title>
</head>
<body>
<h1>foo</h1>
<p>bar hoge</p>
<pre>
fuga
guha
</pre>
<p><hr></p>
</body>
</html>
の場合のYAML形式は
ck1.yaml
- html:
- head:
title: Title
- body:
- h1: foo
- p: bar hoge
- pre: |
fuga
guha
- p:
hr: /
てな具合に。
このYAML形式への「慣れ」が必要ですが、かなりスッキリした感じに見えます。
まずは、こちら方向の変換から。
これは、チョー簡単です。
ezhtml.py
#!/usr/bin/env python
import sys
import yaml
import six
def cv_amp(s, d='enc'):
lst = [ ('&','&'), ('<','<'), ('>','>') ]
if d != 'enc':
lst = reversed(lst)
for (f, t) in lst:
if d != 'enc':
(f, t) = (t, f)
s = s.replace(f, t)
return s
def html_dump(o):
if not o:
return ''
if type(o) == list:
return '\n'.join( map(html_dump, o) )
if type(o) == dict:
(tag, v) = list( o.items() )[0]
s = '<' + tag + '>'
if v != '/':
s += html_dump(v) + '</' + tag.split(' ')[0] + '>'
return s
return cv_amp(o)
if __name__ == "__main__":
fi = sys.stdin if six.PY2 else sys.stdin.buffer
s = fi.read()
s = unicode(s, 'utf-8') if six.PY2 else s.decode()
o = yaml.load(s)
s = html_dump(o) + '\n'
s = s.encode('utf-8') if six.PY2 else s.encode()
fo = sys.stdout if six.PY2 else sys.stdout.buffer
fo.write(s)
# EOF
python2, python3 でも動くようにとした箇所がちょっと煩雑ですが、 核心部分はシンプルです。
$ cat ck1.yaml | ./ezhtml.py <html><head><title>Title</title></head> <body><h1>foo</h1> <p>bar hoge</p> <pre> fuga guha </pre> <p><hr></p></body></html> $ cat ck1.html <html> <head> <title>Title</title> </head> <body> <h1>foo</h1> <p>bar hoge</p> <pre> fuga guha </pre> <p><hr></p> </body> </html>
改行の違いはしょうがないのでOK。
漢字が扱えるように対応しておきます。
nkfのお力を借ります。
pythonでとりあえずutf-8で読み込んで、内部はunicodeで処理します。
python2 と python3 で、その辺りの文字列の取り扱いの変更がややこしそうですが...
nkf.py を作ってみたので、ここで吸収させる事にします。
v2.patch
diff -urN v1/ezhtml.py v2/ezhtml.py
--- v1/ezhtml.py 2018-09-16 16:32:39.000000000 +0900
+++ v2/ezhtml.py 2018-09-17 00:15:20.000000000 +0900
@@ -3,6 +3,7 @@
import sys
import yaml
import six
+import nkf
def cv_amp(s, d='enc'):
lst = [ ('&','&'), ('<','<'), ('>','>') ]
@@ -28,15 +29,16 @@
return cv_amp(o)
if __name__ == "__main__":
- fi = sys.stdin if six.PY2 else sys.stdin.buffer
- s = fi.read()
- s = unicode(s, 'utf-8') if six.PY2 else s.decode()
+ b = nkf.get_stdin()
+ opt = nkf.guess(b)
+ u8 = nkf.cvt(b, '-u')
+ s = nkf.dec(u8)
o = yaml.load(s)
s = html_dump(o) + '\n'
- s = s.encode('utf-8') if six.PY2 else s.encode()
- fo = sys.stdout if six.PY2 else sys.stdout.buffer
- fo.write(s)
+ u8 = nkf.enc(s)
+ b = nkf.cvt(u8, opt)
+ nkf.put_stdout(b)
# EOF
diff -urN v1/nkf.py v2/nkf.py
--- v1/nkf.py 1970-01-01 09:00:00.000000000 +0900
+++ v2/nkf.py 2018-09-17 00:15:20.000000000 +0900
@@ -0,0 +1,55 @@
+#!/usr/bin/env python
+
+import sys
+import six
+import subprocess
+
+PIPE = subprocess.PIPE
+
+enc = lambda s: s.encode('utf-8') if six.PY2 else s.encode()
+dec = lambda b: unicode(b, 'utf-8') if six.PY2 else b.decode()
+
+def do_cmd(cmd, in_b):
+ cmd = enc(cmd)
+ proc = subprocess.Popen(cmd, shell=True, stdin=PIPE, stdout=PIPE)
+ proc.stdin.write(in_b)
+ proc.stdin.close()
+ r = proc.stdout.read()
+ proc.wait()
+ return r # out_b
+
+def get_stdin():
+ fi = sys.stdin if six.PY2 else sys.stdin.buffer
+ return fi.read() # b
+
+def put_stdout(b):
+ fo = sys.stdout if six.PY2 else sys.stdout.buffer
+ fo.write(b)
+
+def guess(b):
+ b = do_cmd('nkf -g', b)
+ return dec(b).strip()
+
+def cvt(b, opt):
+ if opt == 'ASCII':
+ return b
+ d = {
+ 'ISO-2022-JP': '-j',
+ 'EUC-JP': '-e',
+ 'Shift_JIS': '-s',
+ 'UTF-8': '-u',
+ }
+ if opt not in d.values():
+ opt = d.get(opt, '-u')
+ return do_cmd('nkf ' + opt, b)
+
+if __name__ == "__main__":
+ b = get_stdin()
+ opt = guess(b)
+ u8 = cvt(b, '-u')
+ s = dec(u8)
+ # ...
+ u8 = enc(s)
+ b = cvt(u8, opt)
+ put_stdout(b)
+# EOF
$ cat v2.patch | patch -p1
$ cat nkf.py
#!/usr/bin/env python
import sys
import six
import subprocess
PIPE = subprocess.PIPE
enc = lambda s: s.encode('utf-8') if six.PY2 else s.encode()
dec = lambda b: unicode(b, 'utf-8') if six.PY2 else b.decode()
def do_cmd(cmd, in_b):
cmd = enc(cmd)
proc = subprocess.Popen(cmd, shell=True, stdin=PIPE, stdout=PIPE)
proc.stdin.write(in_b)
proc.stdin.close()
r = proc.stdout.read()
proc.wait()
return r # out_b
def get_stdin():
fi = sys.stdin if six.PY2 else sys.stdin.buffer
return fi.read() # b
def put_stdout(b):
fo = sys.stdout if six.PY2 else sys.stdout.buffer
fo.write(b)
def guess(b):
b = do_cmd('nkf -g', b)
return dec(b).strip()
def cvt(b, opt):
if opt == 'ASCII':
return b
d = {
'ISO-2022-JP': '-j',
'EUC-JP': '-e',
'Shift_JIS': '-s',
'UTF-8': '-u',
}
if opt not in d.values():
opt = d.get(opt, '-u')
return do_cmd('nkf ' + opt, b)
if __name__ == "__main__":
b = get_stdin()
opt = guess(b)
u8 = cvt(b, '-u')
s = dec(u8)
# ...
u8 = enc(s)
b = cvt(u8, opt)
put_stdout(b)
# EOF
$
mainの箇所の例では
$ cat jis.yaml | nkf -g
ISO-2022-JP
$ cat jis.yaml | nkf -u
- html:
- head:
title: タイトル
- body:
- h1: ふー
- p: ばー ほげ
- pre: |
ふが
ぐは
- p:
hr: /
$ chmod +x nkf.py
$ cat jis.yaml | ./nkf.py | nkf -g
ISO-2022-JP
$ cat jis.yaml | ./nkf.py | diff jis.yaml -
$
JISコードからUTF-8, unicode を経て UTF-8, JISコードに戻って、一致。
同様にEUCの場合も
$ cat jis.yaml | nkf -e | tee euc.yaml | ./nkf.py | nkf -g EUC-JP $ cat euc.yaml | ./nkf.py | diff euc.yaml - $
その他
$ cat jis.yaml | nkf -s | tee sjis.yaml | ./nkf.py | nkf -g
Shift_JIS
$ cat sjis.yaml | ./nkf.py | diff sjis.yaml -
$
$ cat jis.yaml | nkf -u | tee utf8.yaml | ./nkf.py | nkf -g
UTF-8
$ cat utf8.yaml | ./nkf.py | diff utf8.yaml -
$
$ cat ck1.yaml
- html:
- head:
title: Title
- body:
- h1: foo
- p: bar hoge
- pre: |
fuga
guha
- p:
hr: /
$ cat ck1.yaml | nkf -g
ASCII
$ cat ck1.yaml | ./nkf.py
- html:
- head:
title: Title
- body:
- h1: foo
- p: bar hoge
- pre: |
fuga
guha
- p:
hr: /
$ cat ck1.yaml | ./nkf.py | diff ck1.yaml -
$
上記はpython3の環境で試しているので、同じ事をpython2でも確認しておきます。
$ cat jis.yaml | python2 ./nkf.py | diff jis.yaml - $ cat euc.yaml | python2 ./nkf.py | diff euc.yaml - $ cat sjis.yaml | python2 ./nkf.py | diff sjis.yaml - $ cat utf8.yaml | python2 ./nkf.py | diff utf8.yaml - $ cat ck1.yaml | python2 ./nkf.py | diff ck1.yaml - $
大丈夫そうですね。
このnkf.pyをezhtml.pyから使うように変更してみました。
$ cat jis.yaml | ./ezhtml.py | nkf -u <html><head><title>タイトル</title></head> <body><h1>ふー</h1> <p>ばー ほげ</p> <pre> ふが ぐは </pre> <p><hr></p></body></html> $ cat jis.yaml | ./ezhtml.py | nkf -g ISO-2022-JP $ cat euc.yaml | ./ezhtml.py | nkf -g EUC-JP $ cat sjis.yaml | ./ezhtml.py | nkf -g Shift_JIS $ cat utf8.yaml | ./ezhtml.py | nkf -g UTF-8 $ cat ck1.yaml | ./ezhtml.py | nkf -g ASCII $ cat ck1.yaml | ./ezhtml.py <html><head><title>Title</title></head> <body><h1>foo</h1> <p>bar hoge</p> <pre> fuga guha </pre> <p><hr></p></body></html>
一応 python2 でも同様に
$ cat jis.yaml | python2 ./ezhtml.py | nkf -u <html><head><title>タイトル</title></head> <body><h1>ふー</h1> <p>ばー ほげ</p> <pre> ふが ぐは </pre> <p><hr></p></body></html> $ cat jis.yaml | python2 ./ezhtml.py | nkf -g ISO-2022-JP $ cat euc.yaml | python2 ./ezhtml.py | nkf -g EUC-JP $ cat sjis.yaml | python2 ./ezhtml.py | nkf -g Shift_JIS $ cat utf8.yaml | python2 ./ezhtml.py | nkf -g UTF-8 $ cat ck1.yaml | python2 ./ezhtml.py | nkf -g ASCII
OK。
標準入力からのデータの形式を自動判定させてみます。
HTMLならYAMLに変換して出力し、HTML以外ならYAMLとみなしてHTMLに変換して出力するようにしてみます。
といっても、今のところはYAMLからHTMLの方向の変換しか実装してませんが...
v3.patch
diff -urN v2/ezhtml.py v3/ezhtml.py
--- v2/ezhtml.py 2018-09-17 00:15:20.000000000 +0900
+++ v3/ezhtml.py 2018-09-17 20:15:22.000000000 +0900
@@ -28,15 +28,23 @@
return s
return cv_amp(o)
+def html_load(s):
+ # ...
+ return { 'html': { 'body': { 'p': 'to be continued' } } }
+
if __name__ == "__main__":
b = nkf.get_stdin()
opt = nkf.guess(b)
+ html = nkf.dec( nkf.do_cmd('file - | grep -i html', b) ).strip()
u8 = nkf.cvt(b, '-u')
s = nkf.dec(u8)
- o = yaml.load(s)
-
- s = html_dump(o) + '\n'
+ if html:
+ o = html_load(s)
+ s = yaml.dump( o, default_flow_style=False )
+ else:
+ o = yaml.load(s)
+ s = html_dump(o) + '\n'
u8 = nkf.enc(s)
b = nkf.cvt(u8, opt)
$ cat v3.patch | patch -p1
$ cat v3.patch
:
if __name__ == "__main__":
b = nkf.get_stdin()
opt = nkf.guess(b)
+ html = nkf.dec( nkf.do_cmd('file - | grep -i html', b) ).strip()
u8 = nkf.cvt(b, '-u')
s = nkf.dec(u8)
:
この1行でHTML形式かどうかを判定します。
fileコマンドの標準入力にデータを与えて、結果の文字列からgrepコマンドでhtmlの文字列を大文字小文字を無視して探します。
$ cat ck1.yaml
- html:
- head:
title: Title
- body:
- h1: foo
- p: bar hoge
- pre: |
fuga
guha
- p:
hr: /
$ cat ck1.yaml | ./ezhtml.py
<html><head><title>Title</title></head>
<body><h1>foo</h1>
<p>bar hoge</p>
<pre>
fuga
guha
</pre>
<p><hr></p></body></html>
$ cat ck1.yaml | ./ezhtml.py | ./ezhtml.py
html:
body:
p: to be continued
HTMLからYAMLへの変換は、乞うご期待。
漢字の確認もいくつか
$ cat jis.yaml | nkf -u
- html:
- head:
title: タイトル
- body:
- h1: ふー
- p: ばー ほげ
- pre: |
ふが
ぐは
- p:
hr: /
$ cat jis.yaml | ./ezhtml.py | nkf -u
<html><head><title>タイトル</title></head>
<body><h1>ふー</h1>
<p>ばー ほげ</p>
<pre>
ふが
ぐは
</pre>
<p><hr></p></body></html>
$ cat jis.yaml | ./ezhtml.py | ./ezhtml.py | nkf -u
html:
body:
p: to be continued
$ cat jis.yaml | nkf -u | ./ezhtml.py
<html><head><title>タイトル</title></head>
<body><h1>ふー</h1>
<p>ばー ほげ</p>
<pre>
ふが
ぐは
</pre>
<p><hr></p></body></html>
$ cat jis.yaml | nkf -u | ./ezhtml.py | ./ezhtml.py
html:
body:
p: to be continued
$ cat jis.yaml | nkf -u | python2 ./ezhtml.py
<html><head><title>タイトル</title></head>
<body><h1>ふー</h1>
<p>ばー ほげ</p>
<pre>
ふが
ぐは
</pre>
<p><hr></p></body></html>
$ cat jis.yaml | nkf -u | python2 ./ezhtml.py | python2 ./ezhtml.py
html:
body:
p: to be continued
OK。
HTMLからYAMLへの変換。
すなわち、HTMLをロードしてpythonのオブジェクトで保持して、 それをPyYAMLでdumpとなります。
とりあえず一発目のHTMLのロードを書いてみました。
v4.patch
diff -urN v3/ezhtml.py v4/ezhtml.py
--- v3/ezhtml.py 2018-09-17 20:15:22.000000000 +0900
+++ v4/ezhtml.py 2018-09-17 23:46:44.000000000 +0900
@@ -28,9 +28,107 @@
return s
return cv_amp(o)
+def get_tag(s):
+ (p, tag) = ('', [])
+
+ while '<' in s:
+ i = s.index('<')
+ (t, s) = ( s[:i], s[i+1:] )
+ p += t
+ tag.append('<')
+ n = s[:1]
+ if n == '/':
+ tag.append('/')
+ s = s[1:]
+ n = s[:1]
+ if n.isalpha():
+ if '>' not in s:
+ err( "not found '>'", 'tag={}'.format(tag) )
+ i = s.index('>')
+ tag = tag[1:] + s[:i].split(' ')
+ s = s[i+1:]
+ break
+ p += ''.join(tag)
+ tag = []
+
+ if not tag:
+ (p, s) = (p+s, '')
+
+ return (p, tag, s)
+
+def start_idx(stk, s):
+ for i in reversed( range( len(stk) ) ):
+ e = stk[i]
+ if type(e) == list and e[0] == s:
+ return i
+ return -1
+
+def solo_tag(e):
+ if type(e) == list:
+ (h, e) = ( '/', e[1:] ) if e[0] == '/' else ('', e)
+ return { h + ' '.join(e): '/' }
+ return e
+
+def solo_tags(lst):
+ return list( map( solo_tag, lst ) )
+
+def untabify(s, n=8):
+ def f(s):
+ r = ''
+ for c in s:
+ if c == '\t':
+ c = ' ' * ( n - len(r) % n )
+ r += c
+ return r
+
+ lst = s.split('\n')
+ lst = map(f, lst)
+ return '\n'.join(lst)
+
+def strip_lst(lst, pre=False):
+ def f(e):
+ if type(e) == dict:
+ return e
+ if pre:
+ while ' \n' in e:
+ e = e.replace(' \n', '\n')
+ return untabify(e)
+ return e.replace('\n', ' ').strip()
+
+ return list( filter( lambda e: e != '', map(f, lst) ) )
+
+def close_tag(lst):
+ tag = lst[0]
+ lst = solo_tags( lst[1:] )
+ lst = strip_lst( lst, tag[0].lower() == 'pre' )
+ v = lst
+ if len(lst) == 1:
+ v = lst[0]
+ elif not lst:
+ v = ''
+ return { ' '.join(tag): v }
+
def html_load(s):
- # ...
- return { 'html': { 'body': { 'p': 'to be continued' } } }
+ stk = []
+ while True:
+ (p, tag, s) = get_tag(s)
+ if not tag:
+ break
+ if p:
+ stk.append( cv_amp(p, 'dec') )
+ if tag[0] != '/':
+ stk.append(tag)
+ continue
+ i = start_idx( stk, tag[1] )
+ if i >= 0:
+ stk = stk[:i] + [ close_tag( stk[i:] ) ]
+ else:
+ stk.append( solo_tag(tag) )
+
+ o = strip_lst( solo_tags(stk) )
+ while type(o) == list and len(o) == 1:
+ o = o[0]
+ return o
if __name__ == "__main__":
b = nkf.get_stdin()
$ cat v4.patch | patch -p1
逆方向のHTMLのダンプに比べるとコードが多いですが、 できるだけシンプルにまとめてみました。
$ cat ck1.html
<html>
<head>
<title>Title</title>
</head>
<body>
<h1>foo</h1>
<p>bar hoge</p>
<pre>
fuga
guha
</pre>
<p><hr></p>
</body>
</html>
$ cat ck1.html | ./ezhtml.py | tee ck2.yaml
html:
- head:
title: Title
- body:
- h1: foo
- p: bar hoge
- pre: "\nfuga\n guha\n"
- p:
hr: /
$ diff ck1.yaml ck2.yaml
1,12c1,9
< - html:
< - head:
< title: Title
< - body:
< - h1: foo
< - p: bar hoge
< - pre: |
<
< fuga
< guha
< - p:
< hr: /
---
> html:
> - head:
> title: Title
> - body:
> - h1: foo
> - p: bar hoge
> - pre: "\nfuga\n guha\n"
> - p:
> hr: /
おっと、最初に手打ちで作ったck1.yaml。 全体を要素数1のリストにしてましたが、 htmlタグ1つなので、全体を辞書にしても大丈夫でした。
あとpreタグ。縦棒「|」の形式でダンプさせたいところ...
$ cat ck2.yaml
html:
- head:
title: Title
- body:
- h1: foo
- p: bar hoge
- pre: "\nfuga\n guha\n"
- p:
hr: /
$ cat ck2.yaml | ./ezhtml.py | tee ck2.html
<html><head><title>Title</title></head>
<body><h1>foo</h1>
<p>bar hoge</p>
<pre>
fuga
guha
</pre>
<p><hr></p></body></html>
$ cat ck1.yaml | ./ezhtml.py | diff ck2.html -
$
$ cat ck2.yaml | ./ezhtml.py | diff ck2.html -
$
$ cat ck2.html | ./ezhtml.py | diff ck2.yaml -
$
$ cat ck2.html
<html><head><title>Title</title></head>
<body><h1>foo</h1>
<p>bar hoge</p>
<pre>
fuga
guha
</pre>
<p><hr></p></body></html>
$ cat ck2.html | ./ezhtml.py
html:
- head:
title: Title
- body:
- h1: foo
- p: bar hoge
- pre: "\nfuga\n guha\n"
- p:
hr: /
$ cat ck2.html | ./ezhtml.py | ./ezhtml.py
<html><head><title>Title</title></head>
<body><h1>foo</h1>
<p>bar hoge</p>
<pre>
fuga
guha
</pre>
<p><hr></p></body></html>
$ cat ck2.html | ./ezhtml.py | ./ezhtml.py | ./ezhtml.py
html:
- head:
title: Title
- body:
- h1: foo
- p: bar hoge
- pre: "\nfuga\n guha\n"
- p:
hr: /
とりあえず動いて嬉しいです。
TODO
preタグのyamlダンプを「|」形式に。
PyYAMLに頼ってる箇所ではありますが...どうしたものか? ぐぐってみると、ヒントが。
「PyYAMLで改行含む文字列の出力結果を変えたい(`|` を使いたい)」
まさにそうです!
参考にさせて頂きました。ありがとうございます。
v5.patch
diff -urN v4/ezhtml.py v5/ezhtml.py
--- v4/ezhtml.py 2018-09-17 23:46:44.000000000 +0900
+++ v5/ezhtml.py 2018-09-18 00:31:27.000000000 +0900
@@ -130,6 +130,18 @@
o = o[0]
return o
+def yaml_dump(o):
+ def represent_str(dumper, instance):
+ tag = 'tag:yaml.org,2002:str'
+ style = '|' if '\n' in instance else None
+ return dumper.represent_scalar( tag, instance, style=style )
+
+ for typ in [ str ] + ( [ unicode ] if six.PY2 else [] ):
+ yaml.add_representer(typ, represent_str)
+
+ u8 = yaml.dump( o, default_flow_style=False, allow_unicode=True, encoding='utf-8' )
+ return nkf.dec(u8)
+
if __name__ == "__main__":
b = nkf.get_stdin()
opt = nkf.guess(b)
@@ -139,7 +151,7 @@
if html:
o = html_load(s)
- s = yaml.dump( o, default_flow_style=False )
+ s = yaml_dump(o)
else:
o = yaml.load(s)
s = html_dump(o) + '\n'
$ cat v5.patch | patch -p1
他 allow_unicode, encoding の引数指定追加で yaml.dump()の漢字対応もしてます。
これでyaml.dump()がutf-8にまで変換してくれるようになったのですが、 後続の共通処理でのutf-8への変換を残しときたいので、 nkf.dec()でunicodeの状態に戻してから、後続に渡すようにしてます。
$ cat ck1.html
<html>
<head>
<title>Title</title>
</head>
<body>
<h1>foo</h1>
<p>bar hoge</p>
<pre>
fuga
guha
</pre>
<p><hr></p>
</body>
</html>
$ cat ck1.html | ./ezhtml.py
html:
- head:
title: Title
- body:
- h1: foo
- p: bar hoge
- pre: |2
fuga
guha
- p:
hr: /
$ cat ck1.html | ./ezhtml.py | ./ezhtml.py
<html><head><title>Title</title></head>
<body><h1>foo</h1>
<p>bar hoge</p>
<pre>
fuga
guha
</pre>
<p><hr></p></body></html>
$ cat ck1.html | ./ezhtml.py | ./ezhtml.py | ./ezhtml.py
html:
- head:
title: Title
- body:
- h1: foo
- p: bar hoge
- pre: |2
fuga
guha
- p:
hr: /
なんか「|」に「2」とか付いてます。
字下げの数を明示的に指定だそうです。ふむふむ。
$ cat jis.html | nkf -u
<html><head><title>タイトル</title></head>
<body><h1>ふー</h1>
<p>ばー ほげ</p>
<pre>
ふが
ぐは
</pre>
<p><hr></p></body></html>
$ cat jis.html | ./ezhtml.py | nkf -u
html:
- head:
title: タイトル
- body:
- h1: ふー
- p: ばー ほげ
- pre: |2
ふが
ぐは
- p:
hr: /
$ cat jis.html | ./ezhtml.py | ./ezhtml.py | nkf -u
<html><head><title>タイトル</title></head>
<body><h1>ふー</h1>
<p>ばー ほげ</p>
<pre>
ふが
ぐは
</pre>
<p><hr></p></body></html>
$ cat jis.html | ./ezhtml.py | ./ezhtml.py | ./ezhtml.py | nkf -u
html:
- head:
title: タイトル
- body:
- h1: ふー
- p: ばー ほげ
- pre: |2
ふが
ぐは
- p:
hr: /
大丈夫そうですね。
$ cat jis.html | ./ezhtml.py > jis.yaml $ cat jis.yaml | ./ezhtml.py | diff jis.html - $ $ cat jis.html | ./ezhtml.py | ./ezhtml.py | diff jis.html - $ cat jis.html | python2 ./ezhtml.py | python2 ./ezhtml.py | diff jis.html - $ cat jis.html | nkf -e > euc.html $ cat euc.html | nkf -g EUC-JP $ cat euc.html | ./ezhtml.py | ./ezhtml.py | diff euc.html - $ cat euc.html | python2 ./ezhtml.py | python2 ./ezhtml.py | diff euc.html - $
OK。
それではひとつ、それがしの トップページ なぞを。
$ wget -q -O- http://kondoh.html.xdomain.jp/index.html | tee top.html | nkf -u
<html>
<head>
<meta http-equiv="Content-Type" content="text/html;charset=iso-2022-jp">
<title> kon </title>
</head>
<body>
<h1> kon page </h1>
<p><hr></p>
<p><img src="beat.jpg"></p>
<p><hr></p>
<ul>
<li><a href="bike-kon.html"> バイク </a>
<li><a href=hist.html> 更新履歴 </a>
<li><a href=me.html> 自己紹介 </a>
<li><a href=java/index.html> Javaのテスト </a>
<li><a href=color-sample.html> 色見本 </a>
<li><a href=qP2240018.jpg> ライトネス Qちゃん 2002年頃 </a>
<li><a href="murakami-sho-ji-090329/index.html"> 村上商事 2009 </a>
<li><a href="copen-090419.jpg"> Copen 2009 湯っぷる </a>
<li><a href="txtbl.html"> 簡単なテキストの表組みツール (C言語) </a>
<li><a href="txtblcnt.html"> TXTBLCNT (簡単なテキストの表組みツールのためのさらなるツール) </a>
<li><a href="midi.html"> SMFを読み込み音の波形データを作るプログラム (C言語) </a>
<li><a href="cui14/index.html"> CUI14 </a>
<li><a href="wf.html"> ワイヤーフレームのプログラム </a>
<li><a href="es16/index.html"> Pythonで作るなんちゃってCインタプリタ </a>
<li><a href="nand17/index.html"> Pythonで作るなんちゃってNANDゲートシミュレータ </a>
<li><a href="tete17/index.html"> テテリス2017夏 </a>
<li><a href="pac/index.html"> パックマンもどき2017秋 </a>
<li><a href="bktool/index.html"> バックアップツール </a>
<li><a href="http://kondoh2.html.xdomain.jp/rt/index.html"> レイトレーシング 2018春 </a>
<li><a href="py3.html"> python3 対応のメモ </a>
<li><a href="ezyaml/index.html"> 簡易なYAMLパーサ 2018夏 </a>
<li><a href="ezhtml/index.html"> 簡易なHTMLパーサ 2018秋 </a>
</ul>
<p><video src="http://kondoh2.html.xdomain.jp/rt/out_v44/fix_1.mp4" controls playsinline></video></p>
<p><video src="http://kondoh2.html.xdomain.jp/rt/out_v62/cut.mp4" controls playsinline></video></p>
<p><hr></p>
</body>
</html>
$ cat top.html | ./ezhtml.py | tee top.yaml | nkf -u
html:
- head:
- meta http-equiv="Content-Type" content="text/html;charset=iso-2022-jp": /
- title: kon
- body:
- h1: kon page
- p:
hr: /
- p:
img src="beat.jpg": /
- p:
hr: /
- ul:
- li: /
- a href="bike-kon.html": バイク
- li: /
- a href=hist.html: 更新履歴
- li: /
- a href=me.html: 自己紹介
- li: /
- a href=java/index.html: Javaのテスト
- li: /
- a href=color-sample.html: 色見本
- li: /
- a href=qP2240018.jpg: ライトネス Qちゃん 2002年頃
- li: /
- a href="murakami-sho-ji-090329/index.html": 村上商事 2009
- li: /
- a href="copen-090419.jpg": Copen 2009 湯っぷる
- li: /
- a href="txtbl.html": 簡単なテキストの表組みツール (C言語)
- li: /
- a href="txtblcnt.html": TXTBLCNT (簡単なテキストの表組みツールのためのさらなるツール)
- li: /
- a href="midi.html": SMFを読み込み音の波形データを作るプログラム (C言語)
- li: /
- a href="cui14/index.html": CUI14
- li: /
- a href="wf.html": ワイヤーフレームのプログラム
- li: /
- a href="es16/index.html": Pythonで作るなんちゃってCインタプリタ
- li: /
- a href="nand17/index.html": Pythonで作るなんちゃってNANDゲートシミュレータ
- li: /
- a href="tete17/index.html": テテリス2017夏
- li: /
- a href="pac/index.html": パックマンもどき2017秋
- li: /
- a href="bktool/index.html": バックアップツール
- li: /
- a href="http://kondoh2.html.xdomain.jp/rt/index.html": レイトレーシング 2018春
- li: /
- a href="py3.html": python3 対応のメモ
- li: /
- a href="ezyaml/index.html": 簡易なYAMLパーサ 2018夏
- li: /
- a href="ezhtml/index.html": 簡易なHTMLパーサ 2018秋
- p:
video src="http://kondoh2.html.xdomain.jp/rt/out_v44/fix_1.mp4" controls playsinline: ''
- p:
video src="http://kondoh2.html.xdomain.jp/rt/out_v62/cut.mp4" controls playsinline: ''
- p:
hr: /
$ cat top.html | ./ezhtml.py | ./ezhtml.py | tee top2.html | nkf -u
<html><head><meta http-equiv="Content-Type" content="text/html;charset=iso-2022-jp">
<title>kon</title></head>
<body><h1>kon page</h1>
<p><hr></p>
<p><img src="beat.jpg"></p>
<p><hr></p>
<ul><li>
<a href="bike-kon.html">バイク</a>
<li>
<a href=hist.html>更新履歴</a>
<li>
<a href=me.html>自己紹介</a>
<li>
<a href=java/index.html>Javaのテスト</a>
<li>
<a href=color-sample.html>色見本</a>
<li>
<a href=qP2240018.jpg>ライトネス Qちゃん 2002年頃</a>
<li>
<a href="murakami-sho-ji-090329/index.html">村上商事 2009</a>
<li>
<a href="copen-090419.jpg">Copen 2009 湯っぷる</a>
<li>
<a href="txtbl.html">簡単なテキストの表組みツール (C言語)</a>
<li>
<a href="txtblcnt.html">TXTBLCNT (簡単なテキストの表組みツールのためのさらなるツール)</a>
<li>
<a href="midi.html">SMFを読み込み音の波形データを作るプログラム (C言語)</a>
<li>
<a href="cui14/index.html">CUI14</a>
<li>
<a href="wf.html">ワイヤーフレームのプログラム</a>
<li>
<a href="es16/index.html">Pythonで作るなんちゃってCインタプリタ</a>
<li>
<a href="nand17/index.html">Pythonで作るなんちゃってNANDゲートシミュレータ</a>
<li>
<a href="tete17/index.html">テテリス2017夏</a>
<li>
<a href="pac/index.html">パックマンもどき2017秋</a>
<li>
<a href="bktool/index.html">バックアップツール</a>
<li>
<a href="http://kondoh2.html.xdomain.jp/rt/index.html">レイトレーシング 2018春</a>
<li>
<a href="py3.html">python3 対応のメモ</a>
<li>
<a href="ezyaml/index.html">簡易なYAMLパーサ 2018夏</a>
<li>
<a href="ezhtml/index.html">簡易なHTMLパーサ 2018秋</a></ul>
<p><video src="http://kondoh2.html.xdomain.jp/rt/out_v44/fix_1.mp4" controls playsinline></video></p>
<p><video src="http://kondoh2.html.xdomain.jp/rt/out_v62/cut.mp4" controls playsinline></video></p>
<p><hr></p></body></html>
liタグの改行がアダとなって、逆に視認性が落ちてるような気がしなくもない...?
一応この top2.html をサイトのホームディレクトリにアップロードしてみました。
内容的には大丈夫そうですね。
TODO
それがしの トップページ でHTMLからYAMLの変換を試してみると
<ul> <li><a href="bike-kon.html"> バイク </a> <li><a href=hist.html> 更新履歴 </a> <li><a href=me.html> 自己紹介 </a> : <li><a href="ezhtml/index.html"> 簡易なHTMLパーサ 2018秋 </a> </ul>
な箇所が
- ul:
- li: /
- a href="bike-kon.html": バイク
- li: /
- a href=hist.html: 更新履歴
- li: /
- a href=me.html: 自己紹介
:
- li: /
- a href="ezhtml/index.html": 簡易なHTMLパーサ 2018秋
てな具合に改行が入って、さらにこのYAMLをHTMLに変換しなおすと
<ul><li> <a href="bike-kon.html">バイク</a> <li> <a href=hist.html>更新履歴</a> <li> <a href=me.html>自己紹介</a> : <li> <a href="ezhtml/index.html">簡易なHTMLパーサ 2018秋</a></ul>
ブラウザで表示される内容は同じとは言え、 何とか改行を入れないようにできないでしょうか?
通常のタグは
<tag>foo</tag>
な形式で、'/'で始まる終了タグがついてます。
変換するYAML形式では
tag: foo
の辞書にしてます。
HTMLの場合、この終了タグがないパターンがある訳で、 その場合のYAML形式は
tag: /
の辞書にしてます。
よく考えると終了タグがないパターンは2通りあります。
開始タグだけで意味が完結してる
<tag>
のパターン。
もう一つは
<tag>foo</tag>
で意味が完結するところだが、終了タグが省略されている
<tag>foo
のパターン。
前者はこれまでの対応がふさわしく。
さらに後者のパターンの対応を追加してみます。
これまでの方針
に加えて
先のulタグ、liタグの場合ならば
ul: - li: / - foo - li: / - bar
は
ul: - li /: foo - li /: bar
あるいは
ul: - li/: foo - li/: bar
も許す事にしてみます。
まずはダンプ側の対応から。こちら側の変更は簡単。
v6.patch
diff -urN v5/ezhtml.py v6/ezhtml.py
--- v5/ezhtml.py 2018-09-18 00:31:27.000000000 +0900
+++ v6/ezhtml.py 2018-09-18 21:51:22.000000000 +0900
@@ -15,6 +15,19 @@
s = s.replace(f, t)
return s
+def dump_tag(tag, v):
+ lst = bak = tag.split(' ')
+ if lst[-1] == '/':
+ lst = lst[:-1]
+ if lst[0][-1] == '/':
+ lst = [ lst[0][:-1] ] + lst[1:]
+ s = '<' + ' '.join(lst) + '>'
+ if v != '/':
+ s += html_dump(v)
+ if lst == bak:
+ s += '</' + lst[0] + '>'
+ return s
+
def html_dump(o):
if not o:
return ''
@@ -22,10 +35,7 @@
return '\n'.join( map(html_dump, o) )
if type(o) == dict:
(tag, v) = list( o.items() )[0]
- s = '<' + tag + '>'
- if v != '/':
- s += html_dump(v) + '</' + tag.split(' ')[0] + '>'
- return s
+ return dump_tag(tag, v)
return cv_amp(o)
def get_tag(s):
$ cat v6.patch
diff -urN v5/ezhtml.py v6/ezhtml.py
--- v5/ezhtml.py 2018-09-18 00:31:27.000000000 +0900
+++ v6/ezhtml.py 2018-09-18 21:51:22.000000000 +0900
@@ -15,6 +15,19 @@
s = s.replace(f, t)
return s
+def dump_tag(tag, v):
+ lst = bak = tag.split(' ')
+ if lst[-1] == '/':
+ lst = lst[:-1]
+ if lst[0][-1] == '/':
+ lst = [ lst[0][:-1] ] + lst[1:]
+ s = '<' + ' '.join(lst) + '>'
+ if v != '/':
+ s += html_dump(v)
+ if lst == bak:
+ s += '</' + lst[0] + '>'
+ return s
+
def html_dump(o):
if not o:
return ''
@@ -22,10 +35,7 @@
return '\n'.join( map(html_dump, o) )
if type(o) == dict:
(tag, v) = list( o.items() )[0]
- s = '<' + tag + '>'
- if v != '/':
- s += html_dump(v) + '</' + tag.split(' ')[0] + '>'
- return s
+ return dump_tag(tag, v)
return cv_amp(o)
def get_tag(s):
$ cat v6.patch | patch -p1
ck3.yaml
html:
- head:
title: Title
- body:
- h1: foo
- p: bar hoge
- pre: |
fuga
guha
- p: gundam
- ul:
- li: /
- zaku
- li /: gufu
- li/: dom
- p:
hr: /
もう一丁変換すると...
$ cat ck3.yaml | ./ezhtml.py | ./ezhtml.py
html:
- head:
title: Title
- body:
- h1: foo
- p: bar hoge
- pre: |2
fuga
guha
- p: gundam
- ul:
- li: /
- zaku
- li: /
- gufu
- li: /
- dom
- p:
hr: /
こちら方向の変換は未対応なので、この形式に戻ってしまいます。
では、ロード側。
パース処理の駆動原理は
終了タグの無い場合に、従来の { tag: / } 形式とするか、新設した { tag /: xxx } 形式とするか?
これはもうHTMLのタグの仕様の意味に依ります。
終了タグの省略が許されてる一覧を、データとして持たせる事にします。
すぐ思い当たるのはliタグですが、他には?
それがしの ワイヤーフレーム のページで、終了タグのないものを調べてみます。
$ wget -q -O- http://kondoh.html.xdomain.jp/wf.html | ./ezhtml.py | grep ': /' | sed 's/ *//' | sort | uniq - a: / - br: / - li: / - meta http-equiv="Content-Type" content="text/html;charset=iso-2022-jp": / hr: / img src="wf/img/g1.gif": / img src="wf/img/g10.gif": / : img src="wf/img/w9.png": /
aタグ?
$ wget -q -O- http://kondoh.html.xdomain.jp/wf.html | ./ezhtml.py | less
:
- a: /
- a name="try_repeat_copy":
h2: 繰り返しのパターンを試す
:
対応箇所は
<a> <a name="try_repeat_copy"> <h2> 繰り返しのパターンを試す </h2> </a>
あぁ... 確かに、なんか間違ってる。orz
他は、br, li, meta, hr, img
後続の内容を意味的に含んでいて、終了タグが省略されてるパターンはli。
他のHTMLファイル、例えば
$ wget -q -O- http://kondoh.html.xdomain.jp/py3.html | ./ezhtml.py
Traceback (most recent call last):
File "./ezhtml.py", line 166, in <module>
o = yaml.load(s)
File "/usr/lib/python2.7/dist-packages/yaml/__init__.py", line 71, in load
return loader.get_single_data()
File "/usr/lib/python2.7/dist-packages/yaml/constructor.py", line 37, in get_single_data
node = self.get_single_node()
File "/usr/lib/python2.7/dist-packages/yaml/composer.py", line 36, in get_single_node
document = self.compose_document()
File "/usr/lib/python2.7/dist-packages/yaml/composer.py", line 58, in compose_document
self.get_event()
File "/usr/lib/python2.7/dist-packages/yaml/parser.py", line 118, in get_event
self.current_event = self.state()
File "/usr/lib/python2.7/dist-packages/yaml/parser.py", line 193, in parse_document_end
token = self.peek_token()
File "/usr/lib/python2.7/dist-packages/yaml/scanner.py", line 128, in peek_token
self.fetch_more_tokens()
File "/usr/lib/python2.7/dist-packages/yaml/scanner.py", line 220, in fetch_more_tokens
return self.fetch_value()
File "/usr/lib/python2.7/dist-packages/yaml/scanner.py", line 576, in fetch_value
self.get_mark())
yaml.scanner.ScannerError: mapping values are not allowed here
in "<unicode string>", line 5, column 24:
<style> pre{ background: lightgray; } </style>
^
おおっと。
HTML食わせてるのにyaml.load()?
$ wget -q -O- http://kondoh.html.xdomain.jp/py3.html | file - /dev/stdin: Python script, ASCII text executable, with escape sequences
py3.htmlの内容をfileコマンドがHTMLと思ってくれてない (T_T)
とりあえず、このデータ形式の自動判定の問題は後回し...
$ wget -q -O- http://kondoh.html.xdomain.jp/midi.html | ./ezhtml.py
Traceback (most recent call last):
File "./ezhtml.py", line 158, in <module>
html = nkf.dec( nkf.do_cmd('file - | grep -i html', b) ).strip()
File "/raid5/kondoh/hobby/ezhtml/nkf.py", line 15, in do_cmd
proc.stdin.write(in_b)
IOError: [Errno 32] Broken pipe
$ wget -q -O- http://kondoh.html.xdomain.jp/midi.html | file -
/dev/stdin: HTML document, ASCII text, with very long lines, with escape sequences
これはfileコマンドもHTMLと思っているけど
def do_cmd(cmd, in_b):
cmd = enc(cmd)
proc = subprocess.Popen(cmd, shell=True, stdin=PIPE, stdout=PIPE)
proc.stdin.write(in_b)
データ大き過ぎ?
$ wget -q -O- http://kondoh.html.xdomain.jp/midi.html | wc -l 29020
かも知れません。comunicateを使うべし? 一旦後回し...
とりあえず、終了タグ省略パターンは当面liだけ。 発見次第随時追加という事で。
v7.patch
diff -urN v6/ezhtml.py v7/ezhtml.py
--- v6/ezhtml.py 2018-09-18 21:51:22.000000000 +0900
+++ v7/ezhtml.py 2018-09-18 21:52:05.000000000 +0900
@@ -79,6 +79,39 @@
return { h + ' '.join(e): '/' }
return e
+def is_solo_tag_has_v(e):
+ lst = ['li']
+ if type(e) != dict:
+ return False
+ (tag, v) = e.items()[0]
+ return v == '/' and tag.split(' ')[0] in lst
+
+def solo_tag_has_v_idx(lst):
+ for i in range( len(lst) ):
+ if is_solo_tag_has_v( lst[i] ):
+ return i
+ return -1
+
+def strip_lst1(o):
+ while type(o) == list and len(o) == 1:
+ o = o[0]
+ return o
+
+def solo_tags_modify(lst):
+ def div_lst(lst):
+ i = solo_tag_has_v_idx(lst)
+ return ( lst[:i], lst[i:] ) if i >= 0 else ( lst, [] )
+ r = []
+ while lst:
+ (p, lst) = div_lst(lst)
+ r += p
+ if lst:
+ (e, lst) = ( lst[0], lst[1:] )
+ (tag, v) = e.items()[0] # v == '/'
+ (p, lst) = div_lst(lst)
+ r += [ { tag + ' /': strip_lst1(p) } ]
+ return r
+
def solo_tags(lst):
return list( map( solo_tag, lst ) )
@@ -95,7 +128,7 @@
lst = map(f, lst)
return '\n'.join(lst)
-def strip_lst(lst, pre=False):
+def strip_lst(lst, pre):
def f(e):
if type(e) == dict:
return e
@@ -107,10 +140,16 @@
return list( filter( lambda e: e != '', map(f, lst) ) )
+def close_solo_tag(lst, pre=False):
+ lst = solo_tags(lst)
+ lst = strip_lst(lst, pre)
+ lst = solo_tags_modify(lst)
+ return lst
+
def close_tag(lst):
- tag = lst[0]
- lst = solo_tags( lst[1:] )
- lst = strip_lst( lst, tag[0].lower() == 'pre' )
+ (tag, lst) = ( lst[0], lst[1:] )
+ lst = close_solo_tag( lst, tag[0].lower() == 'pre' )
+
v = lst
if len(lst) == 1:
v = lst[0]
@@ -135,10 +174,8 @@
else:
stk.append( solo_tag(tag) )
- o = strip_lst( solo_tags(stk) )
- while type(o) == list and len(o) == 1:
- o = o[0]
- return o
+ o = close_solo_tag(stk)
+ return strip_lst1(o)
def yaml_dump(o):
def represent_str(dumper, instance):
$ cat v7.patch | patch -p1
is_solo_tag_has_v()冒頭の lst = ['li'] が終了タグ省略パターンのデータです。
$ cat ck3.yaml
html:
- head:
title: Title
- body:
- h1: foo
- p: bar hoge
- pre: |
fuga
guha
- p: gundam
- ul:
- li: /
- zaku
- li /: gufu
- li/: dom
- p:
hr: /
$ cat ck3.yaml | ./ezhtml.py | tee ck3.html
<html><head><title>Title</title></head>
<body><h1>foo</h1>
<p>bar hoge</p>
<pre>
fuga
guha
</pre>
<p>gundam</p>
<ul><li>
zaku
<li>gufu
<li>dom</ul>
<p><hr></p></body></html>
$ cat ck3.yaml | ./ezhtml.py | ./ezhtml.py
html:
- head:
title: Title
- body:
- h1: foo
- p: bar hoge
- pre: |2
fuga
guha
- p: gundam
- ul:
- li /: zaku
- li /: gufu
- li /: dom
- p:
hr: /
$ cat ck3.yaml | ./ezhtml.py | ./ezhtml.py | diff ck3.yaml -
7c7
< - pre: |
---
> - pre: |2
13,14c13
< - li: /
< - zaku
---
> - li /: zaku
16c15
< - li/: dom
---
> - li /: dom
$ cat ck3.yaml | ./ezhtml.py | ./ezhtml.py | ./ezhtml.py
<html><head><title>Title</title></head>
<body><h1>foo</h1>
<p>bar hoge</p>
<pre>
fuga
guha
</pre>
<p>gundam</p>
<ul><li>zaku
<li>gufu
<li>dom</ul>
<p><hr></p></body></html>
$ cat ck3.yaml | ./ezhtml.py | ./ezhtml.py | ./ezhtml.py | diff ck3.html -
9,10c9
< <ul><li>
< zaku
---
> <ul><li>zaku
なんとも...徐々に、liタグまわりの形式や改行が統一されてきます。
では トップページ で確認
$ wget -q -O- http://kondoh.html.xdomain.jp/index.html | tee top.html | nkf -u
<html>
<head>
<meta http-equiv="Content-Type" content="text/html;charset=iso-2022-jp">
<title> kon </title>
</head>
<body>
<h1> kon page </h1>
<p><hr></p>
<p><img src="beat.jpg"></p>
<p><hr></p>
<ul>
<li><a href="bike-kon.html"> バイク </a>
<li><a href=hist.html> 更新履歴 </a>
<li><a href=me.html> 自己紹介 </a>
<li><a href=java/index.html> Javaのテスト </a>
<li><a href=color-sample.html> 色見本 </a>
<li><a href=qP2240018.jpg> ライトネス Qちゃん 2002年頃 </a>
<li><a href="murakami-sho-ji-090329/index.html"> 村上商事 2009 </a>
<li><a href="copen-090419.jpg"> Copen 2009 湯っぷる </a>
<li><a href="txtbl.html"> 簡単なテキストの表組みツール (C言語) </a>
<li><a href="txtblcnt.html"> TXTBLCNT (簡単なテキストの表組みツールのためのさらなるツール) </a>
<li><a href="midi.html"> SMFを読み込み音の波形データを作るプログラム (C言語) </a>
<li><a href="cui14/index.html"> CUI14 </a>
<li><a href="wf.html"> ワイヤーフレームのプログラム </a>
<li><a href="es16/index.html"> Pythonで作るなんちゃってCインタプリタ </a>
<li><a href="nand17/index.html"> Pythonで作るなんちゃってNANDゲートシミュレータ </a>
<li><a href="tete17/index.html"> テテリス2017夏 </a>
<li><a href="pac/index.html"> パックマンもどき2017秋 </a>
<li><a href="bktool/index.html"> バックアップツール </a>
<li><a href="http://kondoh2.html.xdomain.jp/rt/index.html"> レイトレーシング 2018春 </a>
<li><a href="py3.html"> python3 対応のメモ </a>
<li><a href="ezyaml/index.html"> 簡易なYAMLパーサ 2018夏 </a>
<li><a href="ezhtml/index.html"> 簡易なHTMLパーサ 2018秋 </a>
</ul>
<p><video src="http://kondoh2.html.xdomain.jp/rt/out_v44/fix_1.mp4" controls playsinline></video></p>
<p><video src="http://kondoh2.html.xdomain.jp/rt/out_v62/cut.mp4" controls playsinline></video></p>
<p><hr></p>
</body>
</html>
$ cat top.html | ./ezhtml.py | tee top.yaml | nkf -u
html:
- head:
- meta http-equiv="Content-Type" content="text/html;charset=iso-2022-jp": /
- title: kon
- body:
- h1: kon page
- p:
hr: /
- p:
img src="beat.jpg": /
- p:
hr: /
- ul:
- li /:
a href="bike-kon.html": バイク
- li /:
a href=hist.html: 更新履歴
- li /:
a href=me.html: 自己紹介
- li /:
a href=java/index.html: Javaのテスト
- li /:
a href=color-sample.html: 色見本
- li /:
a href=qP2240018.jpg: ライトネス Qちゃん 2002年頃
- li /:
a href="murakami-sho-ji-090329/index.html": 村上商事 2009
- li /:
a href="copen-090419.jpg": Copen 2009 湯っぷる
- li /:
a href="txtbl.html": 簡単なテキストの表組みツール (C言語)
- li /:
a href="txtblcnt.html": TXTBLCNT (簡単なテキストの表組みツールのためのさらなるツール)
- li /:
a href="midi.html": SMFを読み込み音の波形データを作るプログラム (C言語)
- li /:
a href="cui14/index.html": CUI14
- li /:
a href="wf.html": ワイヤーフレームのプログラム
- li /:
a href="es16/index.html": Pythonで作るなんちゃってCインタプリタ
- li /:
a href="nand17/index.html": Pythonで作るなんちゃってNANDゲートシミュレータ
- li /:
a href="tete17/index.html": テテリス2017夏
- li /:
a href="pac/index.html": パックマンもどき2017秋
- li /:
a href="bktool/index.html": バックアップツール
- li /:
a href="http://kondoh2.html.xdomain.jp/rt/index.html": レイトレーシング 2018春
- li /:
a href="py3.html": python3 対応のメモ
- li /:
a href="ezyaml/index.html": 簡易なYAMLパーサ 2018夏
- li /:
a href="ezhtml/index.html": 簡易なHTMLパーサ 2018秋
- p:
video src="http://kondoh2.html.xdomain.jp/rt/out_v44/fix_1.mp4" controls playsinline: ''
- p:
video src="http://kondoh2.html.xdomain.jp/rt/out_v62/cut.mp4" controls playsinline: ''
- p:
hr: /
あぁ、aタグが入る場合は結局改行するのか...
- ul:
- li /: { a href="bike-kon.html": バイク }
- li /: { a href=hist.html: 更新履歴 }
:
などとフロースタイルと混ぜて手打ちすれば、改行なしにもできますが...
ここまですると、かえって見にくいように思えます。
liタグは一旦ここまで。
$ cat top.html | ./ezhtml.py | ./ezhtml.py | nkf -u <html><head><meta http-equiv="Content-Type" content="text/html;charset=iso-2022-jp"> <title>kon</title></head> <body><h1>kon page</h1> <p><hr></p> <p><img src="beat.jpg"></p> <p><hr></p> <ul><li><a href="bike-kon.html">バイク</a> <li><a href=hist.html>更新履歴</a> <li><a href=me.html>自己紹介</a> <li><a href=java/index.html>Javaのテスト</a> <li><a href=color-sample.html>色見本</a> <li><a href=qP2240018.jpg>ライトネス Qちゃん 2002年頃</a> <li><a href="murakami-sho-ji-090329/index.html">村上商事 2009</a> <li><a href="copen-090419.jpg">Copen 2009 湯っぷる</a> <li><a href="txtbl.html">簡単なテキストの表組みツール (C言語)</a> <li><a href="txtblcnt.html">TXTBLCNT (簡単なテキストの表組みツールのためのさらなるツール)</a> <li><a href="midi.html">SMFを読み込み音の波形データを作るプログラム (C言語)</a> <li><a href="cui14/index.html">CUI14</a> <li><a href="wf.html">ワイヤーフレームのプログラム</a> <li><a href="es16/index.html">Pythonで作るなんちゃってCインタプリタ</a> <li><a href="nand17/index.html">Pythonで作るなんちゃってNANDゲートシミュレータ</a> <li><a href="tete17/index.html">テテリス2017夏</a> <li><a href="pac/index.html">パックマンもどき2017秋</a> <li><a href="bktool/index.html">バックアップツール</a> <li><a href="http://kondoh2.html.xdomain.jp/rt/index.html">レイトレーシング 2018春</a> <li><a href="py3.html">python3 対応のメモ</a> <li><a href="ezyaml/index.html">簡易なYAMLパーサ 2018夏</a> <li><a href="ezhtml/index.html">簡易なHTMLパーサ 2018秋</a></ul> <p><video src="http://kondoh2.html.xdomain.jp/rt/out_v44/fix_1.mp4" controls playsinline></video></p> <p><video src="http://kondoh2.html.xdomain.jp/rt/out_v62/cut.mp4" controls playsinline></video></p> <p><hr></p></body></html>
もう一度変換してHTMLに戻すと、良い感じ。
TODO
python3 対応のメモ のHTMLデータをfileコマンドがHTMLと思ってくれない問題について
$ wget -q -O- http://kondoh.html.xdomain.jp/py3.html | file - /dev/stdin: Python script, ASCII text executable, with escape sequences
HTMLじゃなくてpythonのソースと思ってるもよう。
ちょっと試してみると、逆にYAMLデータでも簡単にHTMLと思ってしまうようです。
ck4.yaml
html:
- head:
title: Title
- body:
- h1: foo
- p: <html><head></head><body></body></html>
# EOF
コマンド引数オプションで、強制ありにします。
h の指定があると入力データをHTMLとして扱い、 y の指定があると入力データをYAMLとして扱うようにします。
v8.patch
diff -urN v7/ezhtml.py v8/ezhtml.py
--- v7/ezhtml.py 2018-09-18 21:52:05.000000000 +0900
+++ v8/ezhtml.py 2018-09-18 21:52:28.000000000 +0900
@@ -192,7 +192,10 @@
if __name__ == "__main__":
b = nkf.get_stdin()
opt = nkf.guess(b)
- html = nkf.dec( nkf.do_cmd('file - | grep -i html', b) ).strip()
+
+ is_html = lambda : nkf.dec( nkf.do_cmd('file - | grep -i html', b) ).strip()
+ html = True if 'h' in sys.argv else False if 'y' in sys.argv else is_html()
+
u8 = nkf.cvt(b, '-u')
s = nkf.dec(u8)
$ cat v8.patch
diff -urN v7/ezhtml.py v8/ezhtml.py
--- v7/ezhtml.py 2018-09-18 21:52:05.000000000 +0900
+++ v8/ezhtml.py 2018-09-18 21:52:28.000000000 +0900
@@ -192,7 +192,10 @@
if __name__ == "__main__":
b = nkf.get_stdin()
opt = nkf.guess(b)
- html = nkf.dec( nkf.do_cmd('file - | grep -i html', b) ).strip()
+
+ is_html = lambda : nkf.dec( nkf.do_cmd('file - | grep -i html', b) ).strip()
+ html = True if 'h' in sys.argv else False if 'y' in sys.argv else is_html()
+
u8 = nkf.cvt(b, '-u')
s = nkf.dec(u8)
$ cat v8.patch | patch -p1
ck4.yamlから
$ cat ck4.yaml | ./ezhtml.py - 'html: - head: title: Title - body: - h1: foo - p:' - html: - head: '' - body: ''
YAMLなのにfileコマンドがHTMLと判定してるので、意味不明の出力してますが...
y を指定すると
$ cat ck4.yaml | ./ezhtml.py y | tee ck4.html <html><head><title>Title</title></head> <body><h1>foo</h1> <p><html><head></head><body></body></html></p></body></html>
OK。
一応
ck4.html
<html><head><title>Title</title></head>
<body><h1>foo</h1>
<p><html><head></head><body></body></html></p></body></html>
py3.html では逆に
$ wget -q -O- http://kondoh.html.xdomain.jp/py3.html | ./ezhtml.py
Traceback (most recent call last):
File "./ezhtml.py", line 206, in <module>
o = yaml.load(s)
:
yaml.scanner.ScannerError: mapping values are not allowed here
in "<unicode string>", line 5, column 24:
<style> pre{ background: lightgray; } </style>
^
HTMLをfileコマンドがHTML以外と判定してるので、エラー発生。
h を指定すると
$ wget -q -O- http://kondoh.html.xdomain.jp/py3.html | ./ezhtml.py h | nkf -u
html:
- head:
- meta http-equiv="Content-Type" content="text/html;charset=iso-2022-jp": /
- title: python3
- style: 'pre{ background: lightgray; }'
- body:
- h1: python3 対応のメモ
- p:
- a href="http://kondoh2.html.xdomain.jp/rt/index.html": レイトレーシング 2018春
- の
:
>>> print((1,2))
(1, 2)
>>> print ((1,2))
(1, 2)
- p:
hr: /
OK。
TODO
のHTMLが巨大で顕在化した問題を対策しておきます。
$ wget -q -O- http://kondoh.html.xdomain.jp/midi.html | wc -l
29020
$ wget -q -O- http://kondoh.html.xdomain.jp/midi.html | ./ezhtml.py
Traceback (most recent call last):
File "./ezhtml.py", line 158, in <module>
html = nkf.dec( nkf.do_cmd('file - | grep -i html', b) ).strip()
File "/raid5/kondoh/hobby/ezhtml/nkf.py", line 15, in do_cmd
proc.stdin.write(in_b)
IOError: [Errno 32] Broken pipe
nkf.py の do_cmd() でproc.communicate()を使うように変更してみました。
ついでに python3 で辞書のitems()がlistを返さないため、 うまく動いてなかったバグを、しれっと直しておきます。
v9.patch
diff -urN v8/ezhtml.py v9/ezhtml.py
--- v8/ezhtml.py 2018-09-18 21:52:28.000000000 +0900
+++ v9/ezhtml.py 2018-09-18 22:19:51.000000000 +0900
@@ -28,13 +28,16 @@
s += '</' + lst[0] + '>'
return s
+def get_tag_v(d):
+ return list( d.items() )[0]
+
def html_dump(o):
if not o:
return ''
if type(o) == list:
return '\n'.join( map(html_dump, o) )
if type(o) == dict:
- (tag, v) = list( o.items() )[0]
+ (tag, v) = get_tag_v(o)
return dump_tag(tag, v)
return cv_amp(o)
@@ -83,7 +86,7 @@
lst = ['li']
if type(e) != dict:
return False
- (tag, v) = e.items()[0]
+ (tag, v) = get_tag_v(e)
return v == '/' and tag.split(' ')[0] in lst
def solo_tag_has_v_idx(lst):
@@ -107,7 +110,7 @@
r += p
if lst:
(e, lst) = ( lst[0], lst[1:] )
- (tag, v) = e.items()[0] # v == '/'
+ (tag, v) = get_tag_v(e) # v == '/'
(p, lst) = div_lst(lst)
r += [ { tag + ' /': strip_lst1(p) } ]
return r
diff -urN v8/nkf.py v9/nkf.py
--- v8/nkf.py 2018-09-17 00:15:20.000000000 +0900
+++ v9/nkf.py 2018-09-18 22:20:22.000000000 +0900
@@ -12,11 +12,7 @@
def do_cmd(cmd, in_b):
cmd = enc(cmd)
proc = subprocess.Popen(cmd, shell=True, stdin=PIPE, stdout=PIPE)
- proc.stdin.write(in_b)
- proc.stdin.close()
- r = proc.stdout.read()
- proc.wait()
- return r # out_b
+ return proc.communicate(in_b)[0]
def get_stdin():
fi = sys.stdin if six.PY2 else sys.stdin.buffer
$ cat v9.patch
diff -urN v8/ezhtml.py v9/ezhtml.py
--- v8/ezhtml.py 2018-09-18 21:52:28.000000000 +0900
+++ v9/ezhtml.py 2018-09-18 22:19:51.000000000 +0900
@@ -28,13 +28,16 @@
s += '</' + lst[0] + '>'
return s
+def get_tag_v(d):
+ return list( d.items() )[0]
+
def html_dump(o):
if not o:
return ''
if type(o) == list:
return '\n'.join( map(html_dump, o) )
if type(o) == dict:
- (tag, v) = list( o.items() )[0]
+ (tag, v) = get_tag_v(o)
return dump_tag(tag, v)
return cv_amp(o)
@@ -83,7 +86,7 @@
lst = ['li']
if type(e) != dict:
return False
- (tag, v) = e.items()[0]
+ (tag, v) = get_tag_v(e)
return v == '/' and tag.split(' ')[0] in lst
def solo_tag_has_v_idx(lst):
@@ -107,7 +110,7 @@
r += p
if lst:
(e, lst) = ( lst[0], lst[1:] )
- (tag, v) = e.items()[0] # v == '/'
+ (tag, v) = get_tag_v(e) # v == '/'
(p, lst) = div_lst(lst)
r += [ { tag + ' /': strip_lst1(p) } ]
return r
diff -urN v8/nkf.py v9/nkf.py
--- v8/nkf.py 2018-09-17 00:15:20.000000000 +0900
+++ v9/nkf.py 2018-09-18 22:20:22.000000000 +0900
@@ -12,11 +12,7 @@
def do_cmd(cmd, in_b):
cmd = enc(cmd)
proc = subprocess.Popen(cmd, shell=True, stdin=PIPE, stdout=PIPE)
- proc.stdin.write(in_b)
- proc.stdin.close()
- r = proc.stdout.read()
- proc.wait()
- return r # out_b
+ return proc.communicate(in_b)[0]
def get_stdin():
fi = sys.stdin if six.PY2 else sys.stdin.buffer
$ cat v9.patch | patch -p1
では確認
$ wget -q -O- http://kondoh.html.xdomain.jp/midi.html | ./ezhtml.py | tee midi.yaml | nkf -u
html:
- head:
- meta http-equiv="Content-Type" content="text/html;charset=iso-2022-jp": /
- title: midi
- style: 'pre{ background: lightgray; }'
- body:
- h1: SMFを読み込み音の波形データを作るプログラム (C言語)
- pre:
- "\n\n | "
- font color="#FFFFFF" style="background-color:#000000": ''
- X
:
- p:
hr: /
- p: 工事中...
- p:
hr: /
- <!-- memo $ env RAW_CH=1 ./midi.sh jrt2-sawari.raw jrt2-test --- jrt2.mp3 $
mpg123 -w b.wav jrt2.mp3 $ sox b.wav -t raw -c 1 - > jrt2-mono.raw -rw-rw-r-- 1
kondoh root 50379264 Jun 25 jrt2-mono.raw -rw-rw-r-- 1 kondoh root 100758572
Jun 25 b.wav -->
$ wc -l midi.yaml
25140 midi.yaml
25,000行のYAMLファイルが生成できました。
HTMLに戻してみます。
$ cat midi.yaml | ./ezhtml.py | tee midi2.html | nkf -u
<html><head><meta http-equiv="Content-Type" content="text/html;charset=iso-2022-jp">
<title>midi</title>
<style>pre{ background: lightgray; }</style></head>
<body><h1>SMFを読み込み音の波形データを作るプログラム (C言語)</h1>
<pre>
|
<font color="#FFFFFF" style="background-color:#000000"></font>
X
:
<p><hr></p>
<p>工事中...</p>
<p><hr></p>
<!-- memo $ env RAW_CH=1 ./midi.sh jrt2-sawari.raw jrt2-test --- jrt2.mp3 $ mpg123 -w b.wav jrt2.mp3 $ sox b.wav -t raw -c 1 - > jrt2-mono.raw -rw-rw-r-- 1 kondoh root 50379264 Jun 25 jrt2-mono.raw -rw-rw-r-- 1 kondoh root 100758572 Jun 25 b.wav --></body></html>
$ wc -l midi2.html
24633 midi2.html
24,000行のHTMLファイル生成。
midi2.html 置いてみました。
冒頭の鍵盤の表示が?
<pre> | <font color="#FFFFFF" style="background-color:#000000"> </font>X<font color="#FFFFFF" style="background-color:#000000"> </font> | <font color="#FFFFFF" style="background-color:#000000"><u>X</u></font> <font color="#FFFFFF" style="background-color:#000000"> </font>X<font color="#FFFFFF" style="background-color:#000000"> </font> | <font color="#FFFFFF" style="background-color:#000000"> </font> <font color="#FFFFFF" style="background-color:#000000"> </font> | <font color="#FFFFFF" style="background-color:#000000"> </font> <font color="#FFFFFF" style="background-color:#000000"> </font> <font color="#FFFFFF" style="background-color:#000000"> </font> |
から
<pre> | <font color="#FFFFFF" style="background-color:#000000"></font> X <font color="#FFFFFF" style="background-color:#000000"></font> | <font color="#FFFFFF" style="background-color:#000000"><u>X</u></font> <font color="#FFFFFF" style="background-color:#000000"></font> X <font color="#FFFFFF" style="background-color:#000000"></font> | <font color="#FFFFFF" style="background-color:#000000"></font> <font color="#FFFFFF" style="background-color:#000000"></font> | <font color="#FFFFFF" style="background-color:#000000"></font> <font color="#FFFFFF" style="background-color:#000000"></font> <font color="#FFFFFF" style="background-color:#000000"></font> |
に。あー、preタグの中でfontタグが開いて閉じて、改行入ったか。
他はちゃんと表示されてるか...? 巨大過ぎますね。
最後のHTMLのコメントだった箇所が見えてる?
$ tail midi.yaml
:
- p:
hr: /
- p: 工事中...
- p:
hr: /
- <!-- memo $ env RAW_CH=1 ./midi.sh jrt2-sawari.raw jrt2-test --- jrt2.mp3 $
mpg123 -w b.wav jrt2.mp3 $ sox b.wav -t raw -c 1 - > jrt2-mono.raw -rw-rw-r-- 1
kondoh root 50379264 Jun 25 jrt2-mono.raw -rw-rw-r-- 1 kondoh root 100758572
Jun 25 b.wav -->
なんかhtml_load()で文字列としてスタックに積まれてる?
いづれにせよ、HTMLのコメントはノーマークでした。
TODO
SMFを読み込み音の波形データを作るプログラム (C言語) をYAMLに変換して、HTMLに変換しなおしたものを、 midi2.html として置いてみたのですが、冒頭の鍵盤の表示が...?
preタグの中にさらにタグがあると、改行が入ってしまってる問題の対策です。
v10.patch
diff -urN v9/ezhtml.py v10/ezhtml.py
--- v9/ezhtml.py 2018-09-18 22:19:51.000000000 +0900
+++ v10/ezhtml.py 2018-09-20 03:53:08.000000000 +0900
@@ -15,7 +15,7 @@
s = s.replace(f, t)
return s
-def dump_tag(tag, v):
+def dump_tag(tag, v, pre):
lst = bak = tag.split(' ')
if lst[-1] == '/':
lst = lst[:-1]
@@ -23,7 +23,7 @@
lst = [ lst[0][:-1] ] + lst[1:]
s = '<' + ' '.join(lst) + '>'
if v != '/':
- s += html_dump(v)
+ s += html_dump( v, lst[0].lower() == 'pre' )
if lst == bak:
s += '</' + lst[0] + '>'
return s
@@ -31,14 +31,15 @@
def get_tag_v(d):
return list( d.items() )[0]
-def html_dump(o):
+def html_dump(o, pre=False):
if not o:
return ''
if type(o) == list:
- return '\n'.join( map(html_dump, o) )
+ delim = '' if pre else '\n'
+ return delim.join( map( lambda e: html_dump(e, pre), o ) )
if type(o) == dict:
(tag, v) = get_tag_v(o)
- return dump_tag(tag, v)
+ return dump_tag(tag, v, pre)
return cv_amp(o)
def get_tag(s):
$ cat v10.patch
diff -urN v9/ezhtml.py v10/ezhtml.py
--- v9/ezhtml.py 2018-09-18 22:19:51.000000000 +0900
+++ v10/ezhtml.py 2018-09-20 03:53:08.000000000 +0900
@@ -15,7 +15,7 @@
s = s.replace(f, t)
return s
-def dump_tag(tag, v):
+def dump_tag(tag, v, pre):
lst = bak = tag.split(' ')
if lst[-1] == '/':
lst = lst[:-1]
@@ -23,7 +23,7 @@
lst = [ lst[0][:-1] ] + lst[1:]
s = '<' + ' '.join(lst) + '>'
if v != '/':
- s += html_dump(v)
+ s += html_dump( v, lst[0].lower() == 'pre' )
if lst == bak:
s += '</' + lst[0] + '>'
return s
@@ -31,14 +31,15 @@
def get_tag_v(d):
return list( d.items() )[0]
-def html_dump(o):
+def html_dump(o, pre=False):
if not o:
return ''
if type(o) == list:
- return '\n'.join( map(html_dump, o) )
+ delim = '' if pre else '\n'
+ return delim.join( map( lambda e: html_dump(e, pre), o ) )
if type(o) == dict:
(tag, v) = get_tag_v(o)
- return dump_tag(tag, v)
+ return dump_tag(tag, v, pre)
return cv_amp(o)
def get_tag(s):
$ cat v10.patch | patch -p1
早速、巨大なHTML SMFを読み込み音の波形データを作るプログラム (C言語) で確認
$ wget -q -O- http://kondoh.html.xdomain.jp/midi.html | ./ezhtml.py | ./ezhtml.py | tee midi3.html | nkf -
<html><head><meta http-equiv="Content-Type" content="text/html;charset=iso-2022-jp">
<title>midi</title>
<style>pre{ background: lightgray; }</style></head>
<body><h1>SMFを読み込み音の波形データを作るプログラム (C言語)</h1>
<pre>
| <font color="#FFFFFF" style="background-color:#000000"></font>X<font color="#FFFFFF" style="background-color:#000000"></font> | <font color="#FFFFFF" style="background-color:#000000"><u>X</u></font> <font color="#FFFFFF" style="background-color:#000000"></font>X<font color="#FFFFFF" style="background-color:#000000"></font> | <font color="#FFFFFF" style="background-color:#000000"></font> <font color="#FFFFFF" style="background-color:#000000"></font> | <font color="#FFFFFF" style="background-color:#000000"></font> <font color="#FFFFFF" style="background-color:#000000"></font> <font color="#FFFFFF" style="background-color:#000000"></font> |
<u>| | | | | | | | | | | | | | |</u>
</pre>
<p><hr></p>
:
改行は消えてる様子。
midi3.html 置いてみました。
それでも鍵盤の表示が...変です。
| <font color="#FFFFFF" style="background-color:#000000"> </font>X
に対して
| <font color="#FFFFFF" style="background-color:#000000"></font>
fontタグのスペース1つだけの文字列が消えてました。
preタグ中の他のタグの中身は、strip()したらダメか。
TODO
midi3.html で、それでも鍵盤の表示がおかしい問題。
preタグの中でスペースがstrip()で消えてるようです。
小さいデータで再現確認
$ echo '<html><body><pre>foo<u> </u>bar</pre></body></html>' | file - /dev/stdin: HTML document text $ echo '<html><body><pre>foo<u> </u>bar</pre></body></html>' | ./ezhtml.py | ./ezhtml.py <html><body><pre>foo<u></u>bar</pre></body></html>
確かに<u>と</u>の間のスペースが消えてます。
YAMLに変換した段階は?
$ echo '<html><body><pre>foo<u> </u>bar</pre></body></html>' | ./ezhtml.py
html:
body:
pre:
- foo
- u: ''
- bar
「- u: ''」になってます。
という事はdump側じゃなくてload側の問題。
def strip_lst(lst, pre):
def f(e):
if type(e) == dict:
return e
if pre:
while ' \n' in e:
e = e.replace(' \n', '\n')
return untabify(e)
return e.replace('\n', ' ').strip()
return list( filter( lambda e: e != '', map(f, lst) ) )
ここでpreタグの場合はstrip()通らないはず?
ちょっとdebug out追加してみます
def strip_lst(lst, pre):
def f(e):
if type(e) == dict:
return e
if pre:
while ' \n' in e:
e = e.replace(' \n', '\n')
return untabify(e)
return e.replace('\n', ' ').strip()
print('lst={} pre={}'.format(lst, pre)) # !!! debug
return list( filter( lambda e: e != '', map(f, lst) ) )
$ echo '<html><body><pre>foo<u> </u>bar</pre></body></html>' | ./ezhtml.py
lst=[' '] pre=False
lst=['foo', {'u': ''}, 'bar'] pre=True
lst=[{'pre': ['foo', {'u': ''}, 'bar']}] pre=False
lst=[{'body': {'pre': ['foo', {'u': ''}, 'bar']}}] pre=False
lst=[{'html': {'body': {'pre': ['foo', {'u': ''}, 'bar']}}}] pre=False
html:
body:
pre:
- foo
- u: ''
- bar
ふーむ。uタグを処理する段階ではpre == False。
preの終了タグを見つけた時に、preをTrueにしてスタックを遡りますが、 そのときは既にuタグは処理済...
なのでpreの開始タグでpreをTrueにせねばなりません。
v11.patch
diff -urN v10/ezhtml.py v11/ezhtml.py
--- v10/ezhtml.py 2018-09-20 03:53:08.000000000 +0900
+++ v11/ezhtml.py 2018-09-20 21:28:26.000000000 +0900
@@ -150,9 +150,9 @@
lst = solo_tags_modify(lst)
return lst
-def close_tag(lst):
+def close_tag(lst, pre):
(tag, lst) = ( lst[0], lst[1:] )
- lst = close_solo_tag( lst, tag[0].lower() == 'pre' )
+ lst = close_solo_tag(lst, pre)
v = lst
if len(lst) == 1:
@@ -163,6 +163,12 @@
def html_load(s):
stk = []
+ pre_cnt = 0
+
+ def add_cnt(tag):
+ pre = ( tag[1] if tag[0] == '/' else tag[0] ).lower() == 'pre'
+ return ( -1 if tag[0] == '/' else 1 ) if pre else 0
+
while True:
(p, tag, s) = get_tag(s)
if not tag:
@@ -171,14 +177,16 @@
stk.append( cv_amp(p, 'dec') )
if tag[0] != '/':
stk.append(tag)
+ pre_cnt += add_cnt(tag)
continue
i = start_idx( stk, tag[1] )
if i >= 0:
- stk = stk[:i] + [ close_tag( stk[i:] ) ]
+ stk = stk[:i] + [ close_tag( stk[i:], pre_cnt > 0 ) ]
+ pre_cnt += add_cnt(tag)
else:
stk.append( solo_tag(tag) )
- o = close_solo_tag(stk)
+ o = close_solo_tag( stk, pre_cnt > 0 )
return strip_lst1(o)
def yaml_dump(o):
debug out行は削除して元に戻して
$ cat v11.patch | patch -p1
もっかいdebug out行をつけ直して
def strip_lst(lst, pre):
def f(e):
if type(e) == dict:
return e
if pre:
while ' \n' in e:
e = e.replace(' \n', '\n')
return untabify(e)
return e.replace('\n', ' ').strip()
print('lst={} pre={}'.format(lst, pre)) # !!! debug
return list( filter( lambda e: e != '', map(f, lst) ) )
$ echo '<html><body><pre>foo<u> </u>bar</pre></body></html>' | ./ezhtml.py
lst=[' '] pre=True
lst=['foo', {'u': ' '}, 'bar'] pre=True
lst=[{'pre': ['foo', {'u': ' '}, 'bar']}] pre=False
lst=[{'body': {'pre': ['foo', {'u': ' '}, 'bar']}}] pre=False
lst=[{'html': {'body': {'pre': ['foo', {'u': ' '}, 'bar']}}}] pre=False
html:
body:
pre:
- foo
- u: ' '
- bar
OK。
またdebut out削除して...
$ cat midi.html | ./ezhtml.py | tee midi4.yaml | nkf -u
html:
- head:
- meta http-equiv="Content-Type" content="text/html;charset=iso-2022-jp": /
- title: midi
- style: 'pre{ background: lightgray; }'
- body:
- h1: SMFを読み込み音の波形データを作るプログラム (C言語)
- pre:
- "\n\n | "
- font color="#FFFFFF" style="background-color:#000000": ' '
- X
- font color="#FFFFFF" style="background-color:#000000": ' '
- ' | '
- font color="#FFFFFF" style="background-color:#000000":
u: X
- ' '
- font color="#FFFFFF" style="background-color:#000000": ' '
- X
- font color="#FFFFFF" style="background-color:#000000": ' '
- ' | '
- font color="#FFFFFF" style="background-color:#000000": ' '
- ' '
- font color="#FFFFFF" style="background-color:#000000": ' '
- ' | '
- font color="#FFFFFF" style="background-color:#000000": ' '
- ' '
- font color="#FFFFFF" style="background-color:#000000": ' '
- ' '
- font color="#FFFFFF" style="background-color:#000000": ' '
- " |\n "
- u: '| | | | | | | | | | | | | | | '
- |2+
:
$ cat midi4.yaml | ./ezhtml.py | tee midi4.html | nkf -u
<html><head><meta http-equiv="Content-Type" content="text/html;charset=iso-2022-jp">
<title>midi</title>
<style>pre{ background: lightgray; }</style></head>
<body><h1>SMFを読み込み音の波形データを作るプログラム (C言語)</h1>
<pre>
| <font color="#FFFFFF" style="background-color:#000000"> </font>X<font color="#FFFFFF" style="background-color:#000000"> </font> | <font color="#FFFFFF" style="background-color:#000000"><u>X</u></font> <font color="#FFFFFF" style="background-color:#000000"> </font>X<font color="#FFFFFF" style="background-color:#000000"> </font> | <font color="#FFFFFF" style="background-color:#000000"> </font> <font color="#FFFFFF" style="background-color:#000000"> </font> | <font color="#FFFFFF" style="background-color:#000000"> </font> <font color="#FFFFFF" style="background-color:#000000"> </font> <font color="#FFFFFF" style="background-color:#000000"> </font> |
<u>| | | | | | | | | | | | | | | </u>
</pre>
:
OK。
$ diff midi3.html midi4.html | nkf -u | less 7,8c7,8 < | <font color="#FFFFFF" style="background-color:#000000"></font>X<font color="#FFFFFF" style="background-color:#000000"></font> | <font color="#FFFFFF" style="background-color:#000000"><u>X</u></font> <font color="#FFFFFF" style="background-color:#000000"></font>X<font color="#FFFFFF" style="background-color:#000000"></font> | <font color="#FFFFFF" style="background-color:#000000"></font> <font color="#FFFFFF" style="background-color:#000000"></font> | <font color="#FFFFFF" style="background-color:#000000"></font> <font color="#FFFFFF" style="background-color:#000000"></font> <font color="#FFFFFF" style="background-color:#000000"></font> | < <u>| | | | | | | | | | | | | | |</u> --- > | <font color="#FFFFFF" style="background-color:#000000"> </font>X<font color="#FFFFFF" style="background-color:#000000"> </font> | <font color="#FFFFFF" style="background-color:#000000"><u>X</u></font> <font color="#FFFFFF" style="background-color:#000000"> </font>X<font color="#FFFFFF" style="background-color:#000000"> </font> | <font color="#FFFFFF" style="background-color:#000000"> </font> <font color="#FFFFFF" style="background-color:#000000"> </font> | <font color="#FFFFFF" style="background-color:#000000"> </font> <font color="#FFFFFF" style="background-color:#000000"> </font> <font color="#FFFFFF" style="background-color:#000000"> </font> | > <u>| | | | | | | | | | | | | | | </u> 2746c2746,2748 < <p><a href="midi_mp3_early/prog8_xaa.mp3">prog8_xaa.mp3</a> --- > <p> > > <a href="midi_mp3_early/prog8_xaa.mp3"> prog8_xaa.mp3 </a> 2748,2749c2750,2755 < <a href="midi_mp3_early/prog8_xab.mp3">prog8_xab.mp3</a> < <br></p> --- > > > <a href="midi_mp3_early/prog8_xab.mp3"> prog8_xab.mp3 </a> > <br> > > </p> 6260c6266 < | midi ch : <u>0</u>| | --- > | midi ch : <u>0 </u>| | : 15550c15556 < <a href="midi_mp3/ryd-7.mp3">ryd-7.mp3</a> --- > <a href="midi_mp3/ryd-7.mp3"> ryd-7.mp3 </a> $ diff midi3.html midi4.html | wc -l 828
結構違いが出てますが...
該当箇所を元のmidi.htmlであたると、確かにpreタグの中。
midi4.html 置いてみました。
鍵盤はOK。
他、簡単なデータでデグレないか見ておきます。
$ cat ck1.yaml
- html:
- head:
title: Title
- body:
- h1: foo
- p: bar hoge
- pre: |
fuga
guha
- p:
hr: /
$ cat ck1.yaml | ./ezhtml.py | tee tmp1.html
<html><head><title>Title</title></head>
<body><h1>foo</h1>
<p>bar hoge</p>
<pre>
fuga
guha
</pre>
<p><hr></p></body></html>
$ cat tmp1.html | ./ezhtml.py | tee tmp1.yaml
html:
- head:
title: Title
- body:
- h1: foo
- p: bar hoge
- pre: |2
fuga
guha
- p:
hr: /
$ cat tmp1.html | ./ezhtml.py | diff tmp1.yaml -
$
$ cat tmp1.yaml | ./ezhtml.py | diff tmp1.html -
$
$ cat jis.yaml | nkf -u
- html:
- head:
title: タイトル
- body:
- h1: ふー
- p: ばー ほげ
- pre: |2
ふが
ぐは
- p:
hr: /
$ cat jis.yaml | ./ezhtml.py | tee tmp_jis.html | nkf -u
<html><head><title>タイトル</title></head>
<body><h1>ふー</h1>
<p>ばー ほげ</p>
<pre>
ふが
ぐは
</pre>
<p><hr></p></body></html>
$ cat tmp_jis.html | ./ezhtml.py | tee tmp_jis.yaml | nkf -u
html:
- head:
title: タイトル
- body:
- h1: ふー
- p: ばー ほげ
- pre: |2
ふが
ぐは
- p:
hr: /
$ cat tmp_jis.yaml | ./ezhtml.py | diff tmp_jis.html -
$
$ cat tmp_jis.html | ./ezhtml.py | diff tmp_jis.yaml -
$
$ cat utf8.yaml
- html:
- head:
title: タイトル
- body:
- h1: ふー
- p: ばー ほげ
- pre: |
ふが
ぐは
- p:
hr: /
$ cat utf8.yaml | ./ezhtml.py | tee tmp_utf8.html
<html><head><title>タイトル</title></head>
<body><h1>ふー</h1>
<p>ばー ほげ</p>
<pre>
ふが
ぐは
</pre>
<p><hr></p></body></html>
$ cat tmp_utf8.html | ./ezhtml.py | tee tmp_utf8.yaml
html:
- head:
title: タイトル
- body:
- h1: ふー
- p: ばー ほげ
- pre: |2
ふが
ぐは
- p:
hr: /
$ cat tmp_utf8.yaml | ./ezhtml.py | diff tmp_utf8.html -
$
$ cat tmp_utf8.html | ./ezhtml.py | diff tmp_utf8.yaml -
$
$ cat ck3.yaml
html:
- head:
title: Title
- body:
- h1: foo
- p: bar hoge
- pre: |
fuga
guha
- p: gundam
- ul:
- li: /
- zaku
- li /: gufu
- li/: dom
- p:
hr: /
$ cat ck3.yaml | ./ezhtml.py
<html><head><title>Title</title></head>
<body><h1>foo</h1>
<p>bar hoge</p>
<pre>
fuga
guha
</pre>
<p>gundam</p>
<ul><li>
zaku
<li>gufu
<li>dom</ul>
<p><hr></p></body></html>
$ cat ck3.yaml | ./ezhtml.py | ./ezhtml.py
html:
- head:
title: Title
- body:
- h1: foo
- p: bar hoge
- pre: |2
fuga
guha
- p: gundam
- ul:
- li /: zaku
- li /: gufu
- li /: dom
- p:
hr: /
$ cat ck3.yaml | ./ezhtml.py | ./ezhtml.py | ./ezhtml.py
<html><head><title>Title</title></head>
<body><h1>foo</h1>
<p>bar hoge</p>
<pre>
fuga
guha
</pre>
<p>gundam</p>
<ul><li>zaku
<li>gufu
<li>dom</ul>
<p><hr></p></body></html>
$ cat ck4.yaml | ./ezhtml.py
- 'html: - head: title: Title - body: - h1: foo - p:'
- html:
- head: ''
- body: ''
$ cat ck4.yaml | ./ezhtml.py y
<html><head><title>Title</title></head>
<body><h1>foo</h1>
<p><html><head></head><body></body></html></p></body></html>
$ cat ck4.yaml | ./ezhtml.py y | diff ck4.html -
$
OK。
TODO
HTMLが進化してきたバージョンと、 コメントの規定の変遷の歴史は「微妙で複雑」です。
ここでは「ごちゃごちゃはヌキ」。
簡単なHTMLで現状の動作を確認
comment.html
<html>
<head>
<title>Title</title>
</head>
<body>
<h1>foo</h1>
<!-- comment 1 -->
<p>bar</p>
<!--comment2-->
<!--
<p>hoge</p>
fuga
-->
<pre>
guha
geha
</pre>
<!-- <comment3> -->
</body>
</html>
だめです。
コメントの中のつもりの「<p>hoge</p>」が生きてるし、 そもそも'<!-- ...' が文字列として解釈されてます。
'<!-- xxx -->'はタグと認識しないのだろうか?
def get_tag(s):
(p, tag) = ('', [])
while '<' in s:
i = s.index('<')
(t, s) = ( s[:i], s[i+1:] )
p += t
tag.append('<')
n = s[:1]
if n == '/':
tag.append('/')
s = s[1:]
n = s[:1]
if n.isalpha():
if '>' not in s:
err( "not found '>'", 'tag={}'.format(tag) )
i = s.index('>')
tag = tag[1:] + s[:i].split(' ')
s = s[i+1:]
break
p += ''.join(tag)
tag = []
if not tag:
(p, s) = (p+s, '')
return (p, tag, s)
get_tag() の n.isalpha() の箇所。ここで「はねて」いました。
'<' に続く文字列がアルファベットで始まってなければ、 タグと認識しません。
しかしながらコメントを、 通常の'<'で始まり'>'で終るタグの一種として、簡単に扱ってしまうと
<!-- <p>hoge</p> -->
の場合に、'<p>'の'>'で閉じてしまいます。
終りはちゃんと '-->' で見てやらねばなりません。
あとコメントは、改行も何もかも保持したままでYAMLに変換。 YAMLからHTMLに戻すときに、 正しく元のコメントとして復帰させねばなりません。
オブジェクトの段階ではpreタグのような感じで、 タグ名にあたる辞書のキーはとりあえず '!--' で。
v12.patch
diff -urN v11/ezhtml.py v12/ezhtml.py
--- v11/ezhtml.py 2018-09-20 21:28:26.000000000 +0900
+++ v12/ezhtml.py 2018-09-20 21:28:51.000000000 +0900
@@ -16,6 +16,8 @@
return s
def dump_tag(tag, v, pre):
+ if tag == '!--':
+ return '<!--' + v + '-->'
lst = bak = tag.split(' ')
if lst[-1] == '/':
lst = lst[:-1]
@@ -49,6 +51,13 @@
i = s.index('<')
(t, s) = ( s[:i], s[i+1:] )
p += t
+ if s[:3] == '!--' and '-->' in s[3:]:
+ tag.append('!--')
+ s = s[3:]
+ i = s.index('-->')
+ tag.append( s[:i] )
+ s = s[i+3:]
+ break
tag.append('<')
n = s[:1]
if n == '/':
@@ -79,6 +88,8 @@
def solo_tag(e):
if type(e) == list:
+ if e[0] == '!--':
+ return { '!--': e[1] }
(h, e) = ( '/', e[1:] ) if e[0] == '/' else ('', e)
return { h + ' '.join(e): '/' }
return e
$ cat v12.patch
diff -urN v11/ezhtml.py v12/ezhtml.py
--- v11/ezhtml.py 2018-09-20 21:28:26.000000000 +0900
+++ v12/ezhtml.py 2018-09-20 21:28:51.000000000 +0900
@@ -16,6 +16,8 @@
return s
def dump_tag(tag, v, pre):
+ if tag == '!--':
+ return '<!--' + v + '-->'
lst = bak = tag.split(' ')
if lst[-1] == '/':
lst = lst[:-1]
@@ -49,6 +51,13 @@
i = s.index('<')
(t, s) = ( s[:i], s[i+1:] )
p += t
+ if s[:3] == '!--' and '-->' in s[3:]:
+ tag.append('!--')
+ s = s[3:]
+ i = s.index('-->')
+ tag.append( s[:i] )
+ s = s[i+3:]
+ break
tag.append('<')
n = s[:1]
if n == '/':
@@ -79,6 +88,8 @@
def solo_tag(e):
if type(e) == list:
+ if e[0] == '!--':
+ return { '!--': e[1] }
(h, e) = ( '/', e[1:] ) if e[0] == '/' else ('', e)
return { h + ' '.join(e): '/' }
return e
$ cat v12.patch | patch -p1
簡単なデータから
$ cat comment.html
<html>
<head>
<title>Title</title>
</head>
<body>
<h1>foo</h1>
<!-- comment 1 -->
<p>bar</p>
<!--comment2-->
<!--
<p>hoge</p>
fuga
-->
<pre>
guha
geha
</pre>
<!-- <comment3> -->
</body>
</html>
$ cat comment.html | ./ezhtml.py
html:
- head:
title: Title
- body:
- h1: foo
- '!--': ' comment 1 '
- p: bar
- '!--': comment2
- '!--': |2
<p>hoge</p>
fuga
- pre: |2
guha
geha
- '!--': ' <comment3> '
わりと狙い通りなYAML。
$ cat comment.html | ./ezhtml.py | ./ezhtml.py <html><head><title>Title</title></head> <body><h1>foo</h1> <!-- comment 1 --> <p>bar</p> <!--comment2--> <!-- <p>hoge</p> fuga --> <pre> guha geha </pre> <!-- <comment3> --></body></html>
コメント中の改行も再現できてるようですね。
では、大きなデータで
$ cat midi.html | grep '!--' | head <!-- 04192200 --> <!-- 04202200 --> <!-- 04220000 --> <!-- 04220000 --> <!-- 04220100 --> <!-- 04232300 --> <!-- 04232330 --> <!-- 04240000 --> <!-- 04240100 --> <!-- 04242300 --> $ cat midi.html | grep '!--' | tail <!-- 150909000000 --> <!-- 150910000000 --> <!-- 150911000000 --> o<!-- 150925000000 --> <!-- 150926000000 --> <!-- 150927000000 --> <!-- 150930000000 --> <!-- 151001000000 --> <!-- 151015000000 --> <!-- $ cat midi.html | grep '!--' | wc -l 92
コメントたくさんありますが、末尾の以外は単純っぽいです。
$ cat midi.html | ./ezhtml.py | tee midi.yaml | nkf -u
:
- p:
- cui_midi.c の差分です
- a href="midi_src/cui_midi7.patch": cui_midi7.patch
- '!--': ' 04192200 '
:
- p:
hr: /
- p: 工事中...
- p:
hr: /
- '!--': |2+
memo
$ env RAW_CH=1 ./midi.sh jrt2-sawari.raw jrt2-test
---
jrt2.mp3
$ mpg123 -w b.wav jrt2.mp3
$ sox b.wav -t raw -c 1 - > jrt2-mono.raw
-rw-rw-r-- 1 kondoh root 50379264 Jun 25 jrt2-mono.raw
-rw-rw-r-- 1 kondoh root 100758572 Jun 25 b.wav
...
HTMLに戻してみて
$ cat midi.yaml | ./ezhtml.py > midi5.htm $ tail -20 midi5.html | nkf -u <p><hr></p> <p>工事中...</p> <p><hr></p> <!-- memo $ env RAW_CH=1 ./midi.sh jrt2-sawari.raw jrt2-test --- jrt2.mp3 $ mpg123 -w b.wav jrt2.mp3 $ sox b.wav -t raw -c 1 - > jrt2-mono.raw -rw-rw-r-- 1 kondoh root 50379264 Jun 25 jrt2-mono.raw -rw-rw-r-- 1 kondoh root 100758572 Jun 25 b.wav --></body></html>
オリジナルのmidi.htmlは
$ tail -20 midi.html | nkf -u <!-- memo $ env RAW_CH=1 ./midi.sh jrt2-sawari.raw jrt2-test --- jrt2.mp3 $ mpg123 -w b.wav jrt2.mp3 $ sox b.wav -t raw -c 1 - > jrt2-mono.raw -rw-rw-r-- 1 kondoh root 50379264 Jun 25 jrt2-mono.raw -rw-rw-r-- 1 kondoh root 100758572 Jun 25 b.wav --> </body> </html>
コメント中の改行も問題なさそう。
midi5.html 置いてみました。
OK?
TODO
pythonのユーティリティ・プログラム 2020冬 でうかつにnkf.pyを更新してしまったために、ezhtml.pyでエラーが出る場合がありました。
$ cat ezmhtml.py
:
is_html = lambda : nkf.dec( nkf.do_cmd('file - | grep -i html', b) ).strip()
:
このnkf.do_cmd()がもう消えてしまってました。
ezhtml.pyもkon_utを使うように変更しておきます。
v13.patch
diff -ur v12/ezhtml.py v13/ezhtml.py
--- v12/ezhtml.py 2018-09-20 21:28:51.000000000 +0900
+++ v13/ezhtml.py 2020-02-01 01:15:52.000000000 +0900
@@ -4,6 +4,7 @@
import yaml
import six
import nkf
+import cmd_ut
def cv_amp(s, d='enc'):
lst = [ ('&','&'), ('<','<'), ('>','>') ]
@@ -216,7 +217,7 @@
b = nkf.get_stdin()
opt = nkf.guess(b)
- is_html = lambda : nkf.dec( nkf.do_cmd('file - | grep -i html', b) ).strip()
+ is_html = lambda : nkf.dec( cmd_ut.call_comm('file - | grep -i html', b) ).strip()
html = True if 'h' in sys.argv else False if 'y' in sys.argv else is_html()
u8 = nkf.cvt(b, '-u')
$ cat v13.patch | patch -p1
前回の更新から1年以上経ってますが、久々に更新してみます。
簡易なおれおれマークダウン 2019秋 の方でも更新してて、それとのセットになります。
タグに独自のプロパティ'bare'を追加します。
YAML形式的にはタグのプロパティは、タグ名の部分に押し込められています。
YAML形式で、bare="True" のプロパティがついてると、 &", "<", ">" の3つの文字について、"&", "<", "> のエンコード処理をせずに素通ししてHTMLを生成します。
v14.patch
diff -ur v13/ezhtml.py v14/ezhtml.py
--- v13/ezhtml.py 2020-02-01 01:15:52.000000000 +0900
+++ v14/ezhtml.py 2021-02-23 16:59:50.000000000 +0900
@@ -24,9 +24,17 @@
lst = lst[:-1]
if lst[0][-1] == '/':
lst = [ lst[0][:-1] ] + lst[1:]
+
+ t = 'bare="True"'
+ bare = t in lst
+ if bare:
+ lst.remove(t)
+ if t in bak:
+ bak.remove(t)
+
s = '<' + ' '.join(lst) + '>'
if v != '/':
- s += html_dump( v, lst[0].lower() == 'pre' )
+ s += html_dump( v, lst[0].lower() == 'pre', bare=bare )
if lst == bak:
s += '</' + lst[0] + '>'
return s
@@ -34,7 +42,7 @@
def get_tag_v(d):
return list( d.items() )[0]
-def html_dump(o, pre=False):
+def html_dump(o, pre=False, bare=False):
if not o:
return ''
if type(o) == list:
@@ -43,7 +51,7 @@
if type(o) == dict:
(tag, v) = get_tag_v(o)
return dump_tag(tag, v, pre)
- return cv_amp(o)
+ return o if bare else cv_amp(o)
def get_tag(s):
(p, tag) = ('', [])
$ cat v14.patch | patch -p1
$ ./ezhtml.py <<EOF > - pre: | > abc > xyz <u> foo </u> > bar > - pre bare="True": | > abc > xyz <u> foo </u> > bar > EOF <pre>abc xyz <u> foo </u> bar </pre> <pre>abc xyz <u> foo </u> bar </pre> $