簡単なテキストの字下げツールです。
簡易なHTMLパーサ 2018秋 では、 さんざん実行結果のテキストをYAMLファイルにペーストして編集しました。
emacsを使っているので、編集で字下げの調整は範囲選択してC-x TAB。
複数個ならESC-(繰り返し数) C-x TAB。 あるいは C-x r t 複数のスペース。
これが前者の場合は、結果にtabifyが自動でかかるようで、 行頭に続くスペースはできるだけタブに置き換わります。
後者の場合だとスペースのままですが、空行にも平等にスペースが挿入されます。
YAMLファイルに貼りつける場合、インデントはスペースにしたいけど、 空行は空行のままにしたく。
いちいちuntabifyでスペースに戻しつつ、 あるいはスペースやタブだけの行は、改行だけの空行に手動で修正。
ああ面倒。ということで、自分用のツールです。
$ chmod +x idt.py
$ cat idt.py
#!/usr/bin/env python
import sys
import nkf
def get_opt(k, def_val=None):
n = len(k)
argv = sys.argv[1:]
typ = type(def_val)
for i in range( len(argv) ):
s = argv[i]
if s[:n] == k:
next = lambda : argv[i+1] if argv[i+1:] else ''
v = s[n:] if s[n:] else next()
return typ(v) if def_val != None and type(v) != typ else v
return def_val
def get_tn():
return get_opt('-tn', 8)
def del_tail_spc(s):
while s[-1:] in (' ', '\t'):
s = s[:-1]
return s
def untabify(s):
n = get_tn()
while '\t' in s:
i = s.index('\t')
s = s[:i] + ' ' * ( n - i % n ) + s[i+1:]
return s
def tabify(s):
t = ''
while s[:1] in (' ', '\t'):
t += s[:1]
s = s[1:]
i2tab = lambda i, n: '\t'*(i/n) + ' '*(i%n)
return i2tab( len( untabify(t) ), get_tn() ) + s
def cv(s):
s = del_tail_spc(s)
s = untabify(s)
s = s[ max( get_opt('-d', 0), 0 ) : ]
s = ' ' * max( get_opt('-s', 0), 0 ) + s
s = get_opt('-a', '') + s
s = tabify(s) if get_opt('-t') != None else s
s = del_tail_spc(s)
return s
if __name__ == "__main__":
b = nkf.get_stdin()
opt = nkf.guess(b)
u8 = nkf.cvt(b, '-u')
s = nkf.dec(u8)
s = '\n'.join( map( cv, s.split('\n') ) )
u8 = nkf.enc(s)
b = nkf.cvt(u8, opt)
nkf.put_stdout(b)
# EOF
メインの箇所の感じは、ほぼ 簡易なHTMLパーサ 2018秋 と同じです。
なので nkf.py も、そのまま流用です。
標準入力からのテキストを1行づつ cv() にかけて変換し、 標準出力に出すだけです。
cv()での変換は
さらにもう一つ、瞬間芸のスクリプトを
$ cat ido.sh #!/bin/bash CMD=$(cat) echo $ $CMD echo $CMD | bash # EOF
標準入力からの文字列を、コマンド文字列として表示してからbashに渡して実行するだけのスクリプトです。
$ echo cat ido.sh | ./ido.sh $ cat ido.sh #!/bin/bash CMD=$(cat) echo $ $CMD echo $CMD | bash # EOF
このような具合に「'$' コマンド... 」な1行が出ます。
さらに idt.py で字下げすると
$ echo cat ido.sh | ./ido.sh | ./idt.py -s 4
$ cat ido.sh
#!/bin/bash
CMD=$(cat)
echo $ $CMD
echo $CMD | bash
# EOF
実はこのHTMLファイル。ezhtml.pyで YAMLファイル から変換したものです。 (というか、これからそうするつもりです)
上記の cat ido.sh の箇所も、./ido.sh | ./idt.py -s x で字下げしたものをペーストして作ってます。
YAML形式のソースでは
- pre: |
$ echo cat ido.sh | ./ido.sh | ./idt.py -s 4
$ cat ido.sh
#!/bin/bash
CMD=$(cat)
echo $ $CMD
echo $CMD | bash
# EOF
のような感じです。
この内容を貼りつけるためにさらに
$ echo "echo cat ido.sh | ./ido.sh | ./idt.py -s 4" | ./ido.sh | ./idt.py -s 4
$ echo cat ido.sh | ./ido.sh | ./idt.py -s 4
$ cat ido.sh
#!/bin/bash
CMD=$(cat)
echo $ $CMD
echo $CMD | bash
# EOF
などと以下無限に続く...
削除する側はemacsでC-x r dで十分なので、あまり使わない気もしますが... 一応、動作確認
$ cat ido.sh | ./idt.py -a '>' >#!/bin/bash > >CMD=$(cat) >echo $ $CMD >echo $CMD | bash > ># EOF >$ $ cat ido.sh | ./idt.py -a '>> ' >> #!/bin/bash >> >> CMD=$(cat) >> echo $ $CMD >> echo $CMD | bash >> >> # EOF >>$ $ cat ido.sh | ./idt.py -a '>> ' | ./idt.py -d3 #!/bin/bash CMD=$(cat) echo $ $CMD echo $CMD | bash # EOF $
追加で最後の行がちょっと...な気もしますが、まぁ自分用なのでとりあえずOK
せっかくnkfを使っているので、 指定の漢字エンコーディングでも出せるようにしてみました。
指定する場合は、-oのあとにnkfのオプションに従った1文字で指定します。
指定しない場合は、従来通り入力と同じエンコーディングになります。
$ cat v2.patch | patch -p1
$ cat jis.yaml | nkf -u
- html:
- head:
title: タイトル
- body:
- h1: ふー
- p: ばー ほげ
- pre: |2
ふが
ぐは
- p:
hr: /
$ cat jis.yaml | ./idt.py -a'| ' -ou
| - html:
| - head:
| title: タイトル
| - body:
| - h1: ふー
| - p: ばー ほげ
| - pre: |2
|
| ふが
| ぐは
| - p:
| hr: /
$ cat jis.yaml | ./idt.py -oe -d2 | nkf -g
EUC-JP
$ cat jis.yaml | ./idt.py -oe -d2 | nkf -u
html:
- head:
title: タイトル
- body:
- h1: ふー
- p: ばー ほげ
- pre: |2
ふが
ぐは
- p:
hr: /
nkf.pyの従来の関数の仕様を変えないよう、心がけて変更してみました。
なので更新したnkf.pyを、 簡易なHTMLパーサ 2018秋 の方に戻して使っても問題無いはずです。
$ cat v3.patch | patch -p1
当初からあった
$ cat ido.sh | ./idt.py -a '>' >#!/bin/bash > >CMD=$(cat) >echo $ $CMD >echo $CMD | bash > ># EOF >$
この末尾の問題。
対象のテキストが改行で終ってる場合は、 末尾改行を取り除いて処理し、 変換後に、末尾改行を追加して戻すようにしてみました。
$ cat ido.sh | ./idt.py -a '>' >#!/bin/bash > >CMD=$(cat) >echo $ $CMD >echo $CMD | bash > ># EOF $
idt.py のcv()での変換の順番
このうちの
この2つの変換については、 コマンドラインの指定順に実行するよう変更しました。
$ cat ido.sh | ./idt.py -a '>' -s2 >#!/bin/bash > >CMD=$(cat) >echo $ $CMD >echo $CMD | bash > ># EOF
$ cat ido.sh | ./idt.py -s2 -a '>' > #!/bin/bash > > CMD=$(cat) > echo $ $CMD > echo $CMD | bash > > # EOF
貼付ツール ins.py を追加してみました。
コマンドの実行結果を字下げツール idt.py で字下げしたあと、 テキストファイルの指定の位置に貼り付けるためのツールです。
例えば
$ cat foo.txt | nkf -g
ISO-2022-JP
$ cat foo.txt | nkf -u
1. ヘッダファイル
1.1. 確認方法
/usr/include 以下を調べます。
以上
$
なJISコードのテキストファイルがあったとして、 「以上」の行の前に、次の実行結果をスペース6つ字下げして貼り付けたいならば
$ echo "find /usr/include -type f | head" | ./ido.sh $ find /usr/include -type f | head /usr/include/autosprintf.h /usr/include/monetary.h /usr/include/math.h /usr/include/ifaddrs.h /usr/include/mntent.h /usr/include/inttypes.h /usr/include/dlfcn.h /usr/include/rpc/xdr.h /usr/include/rpc/pmap_prot.h /usr/include/rpc/auth_unix.h
./idt.py -s6 で字下げして
$ echo "find /usr/include -type f | head" | ./ido.sh | ./idt.py -s6
$ find /usr/include -type f | head
/usr/include/autosprintf.h
/usr/include/monetary.h
/usr/include/math.h
/usr/include/ifaddrs.h
/usr/include/mntent.h
/usr/include/inttypes.h
/usr/include/dlfcn.h
/usr/include/rpc/xdr.h
/usr/include/rpc/pmap_prot.h
/usr/include/rpc/auth_unix.h
./ins.py -i foo.txt で貼り付けます。
$ echo "find /usr/include -type f | head" | ./ido.sh | ./idt.py -s6 | ./ins.py -ou -i foo.txt
すると foo.txt の内容が表示されます。
カーソル位置の手前に挿入されるので、 「以上」の行が反転されるようにしてENTERキー入力です。
$ cat foo.txt | nkf -u
1. ヘッダファイル
1.1. 確認方法
/usr/include 以下を調べます。
$ find /usr/include -type f | head
/usr/include/autosprintf.h
/usr/include/monetary.h
/usr/include/math.h
/usr/include/ifaddrs.h
/usr/include/mntent.h
/usr/include/inttypes.h
/usr/include/dlfcn.h
/usr/include/rpc/xdr.h
/usr/include/rpc/pmap_prot.h
/usr/include/rpc/auth_unix.h
以上
$
書き換える前のオリジナルのファイルは foo.txt.0 として残してます。
$ diff foo.txt.0 foo.txt 6a7,17 > $ find /usr/include -type f | head > /usr/include/autosprintf.h > /usr/include/monetary.h > /usr/include/math.h > /usr/include/ifaddrs.h > /usr/include/mntent.h > /usr/include/inttypes.h > /usr/include/dlfcn.h > /usr/include/rpc/xdr.h > /usr/include/rpc/pmap_prot.h > /usr/include/rpc/auth_unix.h $

カーソル行を移動した後、 やっぱり貼り付けせずに取り消したいときは、 「q」キーや「esc」キーで何もせずに終了します。
-h でヘルプ表示。
$ ./ins.py -h Usage: ./ins.py [-o view_enc] [-s ins_str] [-i] fn_i if no -s xxx, use stdin fn_i == '-' use stdin (need -s xxx) -i : in place fn_i (over write)
貼る文字列を -s xxx で指定します。 指定が無ければ標準入力を使います。
貼り付けられる側のテキストファイルは、 ファイル名を指定します。
そのファイル名が'-'のときは標準入力を使います。 この場合、貼る文字列は -s xxx で指定します。
結果のテキストは標準出力に出します。
-i の指定(in place)があれば、標準出力には出さず、 貼り付けられる側のテキストファイルを上書きします。
上書きするときは、オリジナルのファイルを xxx.0 のファイル名で残します。 もし xxx.0 があれば xxx.1, 2, 3... と増えます。
貼り付け位置を決めるときの表示では、 端末のエンコーディング設定に併せて -o でエンコーディングを変更できます。
指定が無ければテキストファイルのエンコーディングのままで表示されます。
貼るテキストは、貼り付けられる側のテキストの漢字エンコーディングに変換されます。
$ cat bar.txt | nkf -g EUC-JP $ cat bar.txt | nkf -u 引用の例 下記の例1の様に行頭に'> 'を追加します。 例1 // $
このEUCのテキスト bar.txt の'//'(の直前)に、 先のJISのテキスト foo.txt の各行頭に'> 'を付けて、さらにスペース2つ字下げして貼り付けるならば
$ cat foo.txt | nkf -g ISO-2022-JP $ cat foo.txt | ./idt.py -a'> ' -s2 | nkf -u > 1. ヘッダファイル > > 1.1. 確認方法 > > /usr/include 以下を調べます。 > > $ find /usr/include -type f | head > /usr/include/autosprintf.h > /usr/include/monetary.h > /usr/include/math.h > /usr/include/ifaddrs.h > /usr/include/mntent.h > /usr/include/inttypes.h > /usr/include/dlfcn.h > /usr/include/rpc/xdr.h > /usr/include/rpc/pmap_prot.h > /usr/include/rpc/auth_unix.h > 以上
なので
$ cat foo.txt | ./idt.py -a'> ' -s2 | ./ins.py -ou -i bar.txt
矢印キーでカーソルを「//」に合わせてENTERキー
$ cat bar.txt | nkf -g EUC-JP
確かにEUCで
$ cat bar.txt | nkf -u 引用の例 下記の例1の様に行頭に'> 'を追加します。 例1 > 1. ヘッダファイル > > 1.1. 確認方法 > > /usr/include 以下を調べます。 > > $ find /usr/include -type f | head > /usr/include/autosprintf.h > /usr/include/monetary.h > /usr/include/math.h > /usr/include/ifaddrs.h > /usr/include/mntent.h > /usr/include/inttypes.h > /usr/include/dlfcn.h > /usr/include/rpc/xdr.h > /usr/include/rpc/pmap_prot.h > /usr/include/rpc/auth_unix.h > 以上 //
-i をつけなければ標準出力にでます。
$ find /usr/include -type f | head > hoge.txt $ cat hoge.txt /usr/include/autosprintf.h /usr/include/monetary.h /usr/include/math.h /usr/include/ifaddrs.h /usr/include/mntent.h /usr/include/inttypes.h /usr/include/dlfcn.h /usr/include/rpc/xdr.h /usr/include/rpc/pmap_prot.h /usr/include/rpc/auth_unix.h $ echo '====================' | ./ins.py hoge.txt > fuga.txt
適当にカーソル移動してENTER
$ cat fuga.txt /usr/include/autosprintf.h /usr/include/monetary.h /usr/include/math.h /usr/include/ifaddrs.h /usr/include/mntent.h ==================== /usr/include/inttypes.h /usr/include/dlfcn.h /usr/include/rpc/xdr.h /usr/include/rpc/pmap_prot.h /usr/include/rpc/auth_unix.h
-s で貼るテキストを指定するならば
$ ./ins.py -s '/////////////////' hoge.txt > guha.txt
適当にカーソル移動してENTER
$ cat guha.txt /usr/include/autosprintf.h /usr/include/monetary.h /usr/include/math.h /usr/include/ifaddrs.h /usr/include/mntent.h ///////////////// /usr/include/inttypes.h /usr/include/dlfcn.h /usr/include/rpc/xdr.h /usr/include/rpc/pmap_prot.h /usr/include/rpc/auth_unix.h
貼られる側を標準入力にするならば
$ cat hoge.txt | ./ins.py -s '|||||||||||||||||||' - > zaku.txt
適当にカーソル移動してENTER
$ cat zaku.txt /usr/include/autosprintf.h /usr/include/monetary.h /usr/include/math.h /usr/include/ifaddrs.h /usr/include/mntent.h ||||||||||||||||||| /usr/include/inttypes.h /usr/include/dlfcn.h /usr/include/rpc/xdr.h /usr/include/rpc/pmap_prot.h /usr/include/rpc/auth_unix.h
今回は盛りだくさんのなので、ソースファイルを細かく分けてみました。
$ (cd v3 ; wc -l *)
10 dbg.py
59 idt.py
84 ins.py
40 key.py
26 newton.py
74 nkf.py
45 opt.py
54 term.py
104 view.py
496 total
いづれも行数少なめです。
今回のins.pyは、標準入力、標準出力をパイプやリダイレクトで使いつつ、 キー入力を受け付けて、画面にも表示を出します。
その辺りのコツは term.py の /dev/tty 使用箇所や key.py に集約されてます。
忘れないうちにメモを書いておきます。
term.py
#!/usr/bin/env python
import subprocess as sp
tty_r = open('/dev/tty', 'r') # 端末からのキー入力用
tty_w = open('/dev/tty', 'w') # 端末への画面出力用
def get_sz(): # 端末のサイズを(w, h)で返します
w = int( sp.check_output('tput cols', shell=True).strip() )
h = int( sp.check_output('tput lines', shell=True).strip() )
return (w, h)
def get_pos(): # 現在のカーソル位置を(x, y)で返します
cmds = [
#'echo -en "\e[6n"',
'echo -en "\x1b[6n"',
'read -sd"[" dmy',
'read -sd"R" row_col',
'echo -n $row_col >&2',
]
cmd = "bash -c '{}'".format( '\n'.join(cmds) )
proc = sp.Popen(cmd, shell=True, stdin=tty_r, stdout=tty_w, stderr=sp.PIPE)
s = proc.communicate()[1].decode()
proc.wait()
(row, col) = map( int, s.split(';') )
(x, y) = (col-1, row-1)
return (x, y)
def stty(s, v=True): # sttyコマンドを実行します
# stty('echo') だと "stty echo < /dev/tty"
# stty('echo', False) だと "stty -echo < /dev/tty"
if not v:
s = '-' + s
cmd = 'stty {} < /dev/tty'.format(s)
sp.call( cmd, shell=True )
def out(s): # 画面に文字列 s を出力
tty_w.write(s)
tty_w.flush()
esc = lambda s: chr(0x1b) + '[' + s # エスケープシーケンス用
loc = lambda x, y: out( esc( '{};{}H'.format(y+1, x+1) ) ) # カーソルを(x, y)に移動
rev = lambda : out( esc('7m') ) # 属性を反転表示に
uline = lambda : out( esc('4m') ) # 属性を下線ありに
reset = lambda : out( esc('0m') ) # 属性をリセットして戻す
cls = lambda : out( esc('2J') ) # 画面クリア
def scroll(m): # 画面をm行スクロール(mが負なら逆方向にスクロール)
am = abs(m)
sm = m / am
v = 'S' if sm > 0 else 'T'
out( esc( '{}{}'.format( am, v ) ) )
# EOF
key.py
#!/usr/bin/env python
import os
import term
esc = term.esc # エスケープシーケンス用
ctl = lambda s: chr( 1 + ord(s) - ord('a') ) # コントロールキー用
def init(): # 初期化処理
term.stty('echo', False) # エコー表示なし
term.stty('icanon', False) # 改行入力なしで反映
def fini(): # 終了処理
term.stty('icanon', True) # 改行入力で反映
term.stty('echo', True) # エコー表示あり
def get(): # 入力キー取得
s = os.read( term.tty_r.fileno(), 10 ) # とりあえず上限は10文字分のシーケンスまで
if type(s) != str: # python3 で bytes で返った場合
s =''.join( map(chr, s) ) # strに変換
# 単に decode() にすると
# Alt+v で返る 0xf6 の場合などではエラーになる
return s
def allow(k): # get()で取得したキーkが矢印キーなどの方向用のものならば
# 上下左右を表す'u','d','l','r'の文字列を返す
# 'pu','pd' はページアップ、ページダウン
# 登録してる方向用のもの以外なら空文字列''を返す
tbls = [[
[ 'u', 'd', 'l', 'r' ],
[ esc('A'), esc('B'), esc('D'), esc('C') ], # allow
[ ctl('p'), ctl('n'), ctl('b'), ctl('f') ], # emacs
[ 'k', 'j', 'h', 'l' ], # vi
],[
[ 'pu', 'pd' ],
[ esc('5~'), esc('6~') ], # allow
[ chr(0xf6), ctl('v') ], # emacs
[ 'b', ' ' ], # less
]]
for tbl in tbls:
for lst in tbl[1:]:
if k in lst:
return tbl[0][ lst.index(k) ]
return ''
# EOF
nkf.py
#!/usr/bin/env python
import sys
import six
import subprocess as sp
enc = lambda s: s.encode('utf-8') if six.PY2 else s.encode() # unicode文字列sをutf-8にエンコード
dec = lambda b: unicode(b, 'utf-8') if six.PY2 else b.decode() # utf-8をunicode文字列にデコード
def do_cmd(cmd, in_b): # 標準入力にバイト列 in_b を与えてcmdを実行
# 結果の標準出力のバイト列を返す
cmd = enc(cmd)
proc = sp.Popen(cmd, shell=True, stdin=sp.PIPE, stdout=sp.PIPE)
return proc.communicate(in_b)[0]
def get_stdin(): # 標準入力から読み出したバイト列を返す
fi = sys.stdin if six.PY2 else sys.stdin.buffer
return fi.read() # b
def put_stdout(b): # 標準出力にバイト列 b を書き込む
fo = sys.stdout if six.PY2 else sys.stdout.buffer
fo.write(b)
opt_dic = { # nkf -g が返す判定結果の表示と、対応するオプション指定の辞書
'ISO-2022-JP': '-j',
'EUC-JP': '-e',
'Shift_JIS': '-s',
'UTF-8': '-u',
'ASCII': '',
}
def guess(b, style_opt=False): # バイト列 b を判定したエンコーディングを返す
# style_opt=True なら上記 opt_dic辞書の値の方の形式で返す
b = do_cmd('nkf -g', b)
opt = dec(b).strip()
return opt_dic.get(opt, '-u') if style_opt else opt
def cvt(b, opt, do_guess=False): # バイト列 b を optで指定したエンコーディングに変換する
# do_guess=Trueなら、b の現在のエンコーディングも調べて、なるべく無駄なコマンド実行を避ける
# ("nkf -g" というコマンド実行は増えるけどね)
if opt not in opt_dic.values():
opt = opt_dic.get(opt, '-u')
if opt == '':
return b
if do_guess:
from_opt = guess(b, True)
if from_opt == '' or from_opt == opt:
return b
return do_cmd('nkf ' + opt, b)
def to_utf8(b): # バイト列 b を utf-8 に
opt = guess(b, True)
u8 = b if opt in ('-u', '') else cvt(b, '-u')
return (u8, opt)
def utf8_to(u8, opt): # utf-8 を optで指定したエンコーディングのバイト列に
return u8 if opt in ('-u', '') else cvt(u8, opt)
def to_str(b): # バイト列 b を unicode文字列に
(u8, opt) = to_utf8(b)
return ( dec(u8), opt )
def str_to(s, opt): # unicode文字列sを、optで指定したエンコーでイングのバイト列に
return utf8_to( enc(s), opt )
def str_width(s): # unicode文字列sを端末に表示したときの、半角英数文字相当の文字数幅を返す
return sum( map( lambda c: 1 if ord(c) < 0x80 else 2, s ) )
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
opt.py
#!/usr/bin/env python
import sys
def get(k, def_val=None): # 文字列 k で始まるオプションの値を返す
# get('-foo', 0) の場合
# 'cmd -foo 3 bar' なら整数3
# 'cmd -foo4 bar' なら整数4
# 'cmd bar' なら整数0
# get('-foo') の場合
# 'cmd -foo 3 bar' なら文字列'3'
# 'cmd -foo4 bar' なら文字列'4'
# 'cmd bar' ならNone
n = len(k)
argv = sys.argv[1:]
typ = type(def_val)
for i in range( len(argv) ):
s = argv[i]
if s[:n] == k:
next = lambda : argv[i+1] if argv[i+1:] else ''
v = s[n:] if s[n:] else next()
return typ(v) if def_val != None and type(v) != typ else v
return def_val
def not_opt_argv(ks_v, ks_0): # オプション指定以外のコマンド引数のリストを返す
# ks_v : key list , key value or keyValue
# ks_0 : key list , key (only)
# ks_v には、値をともなうオプションのキーのリストを
# ks_0 には、値をともなわないオプションのキーのリストを指定する
argv = sys.argv[1:]
argv = list( filter( lambda a: a not in ks_0, argv ) )
def f(a):
for k in ks_v:
if ( lambda n: a[:n] == k and a[n:] )( len(k) ):
return False
return True
argv = list( filter( f, argv ) )
for k in ks_v:
while k in argv:
i = argv.index(k)
argv = argv[:i] + argv[i+2:]
return argv
def index(k): # 文字列 k で始まるオプションのコマンド引数のインデックスを返す
# オプション k の指定がなければ -1 を返す
# 先頭の実行コマンド文字列は除外して考える
n = len(k)
argv = sys.argv[1:]
for i in range( len(argv) ):
s = argv[i]
if s[:n] == k:
return i
return -1
# EOF
dbg.py
#!/usr/bin/env python
# あらかじめ別の端末で
# $ mkfifo /tmp/fifo
# $ cat /tmp/fifo
# を実行して待機させておく
import sys
fifo = open('/tmp/fifo', 'w') # あらかじめ作成しておいた /tmp/fifo をオープン
def out(s): # /tmp/fifo に文字列sを書き込んでフラッシュする
# cat /tmp/fifo してる端末に文字列が表示される
fifo.write(s + '\n')
fifo.flush()
# EOF
newton.py
#!/usr/bin/env python
def get_int(f, l, r): # 整数用の簡易ニュートン法
# f は1つの整数を引数として、整数か少数の値を返す関数
# l, rは関数の定義域
# というかf(x) = 0のxが存在するであろう範囲の上限と下限(逆でもOK)
# f(x) = 0 となるxを求めて返す
# f(x) = 0 にならない場合は、なるべく0に近くなるxを返す
c = int( (l + r) / 2 )
if l == r:
return c
(vl, vr) = ( f(l), f(r) )
if vl * vr == 0:
return c if vl + vr == 0 else ( l if vl == 0 else r )
if vl * vr > 0:
return c
while abs(l - r) > 1:
c = int( (l + r) / 2 )
vc = f(c)
if vc == 0:
return c
if vc * vl > 0:
(l, vl) = (c, vc)
else:
(r, vr) = (c, vc)
(al, ar) = ( abs(vl), abs(vr) )
return min(l, r) if al == ar else ( l if al < ar else r )
# EOF