字下げツール

簡単なテキストの字下げツールです。

簡易なHTMLパーサ 2018秋 では、 さんざん実行結果のテキストをYAMLファイルにペーストして編集しました。

emacsを使っているので、編集で字下げの調整は範囲選択してC-x TAB。

複数個ならESC-(繰り返し数) C-x TAB。 あるいは C-x r t 複数のスペース。

これが前者の場合は、結果にtabifyが自動でかかるようで、 行頭に続くスペースはできるだけタブに置き換わります。

後者の場合だとスペースのままですが、空行にも平等にスペースが挿入されます。

YAMLファイルに貼りつける場合、インデントはスペースにしたいけど、 空行は空行のままにしたく。

いちいちuntabifyでスペースに戻しつつ、 あるいはスペースやタブだけの行は、改行だけの空行に手動で修正。

ああ面倒。ということで、自分用のツールです。



バージョン1

$ 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()での変換は

さらにもう一つ、瞬間芸のスクリプトを

ido.sh

$ 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


バージョン2

せっかくnkfを使っているので、 指定の漢字エンコーディングでも出せるようにしてみました。

指定する場合は、-oのあとにnkfのオプションに従った1文字で指定します。

指定しない場合は、従来通り入力と同じエンコーディングになります。

v2.patch

jis.yaml

$ 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秋 の方に戻して使っても問題無いはずです。


バージョン3 (貼付ツール)

v3.patch

$ 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