SKK-jisyoファイルのCDB化

SKK の辞書ファイルを CDB (constant database) にしました。現在の ddskk の Makefile からは、辞書ファイルを CDB 化するためのターゲットが取り除かれているため、自前で作成します。ファイルそのものの生成は、MacPorts 経由で取得した cdbmake コマンドを使用し、SKK 辞書ファイルを cdbmake コマンドが読み込めるように整形するためのスクリプトを書きました。

# 辞書ファイルのとあるエントリ
よみこn /読み込/読込/詠み込;詩歌の中に入れる/

# 以下に整形する
+10,53:よみこn->/読み込/読込/詠み込;詩歌の中に入れる/

awk や nkf コマンドとの組み合わせでとても簡単に実現できそうですが、辞書バッファのコーディングを utf-8 としたかったことと、Python3 の concurrent.futures を使ってみたかったため、Python です。以前インストールしたときには cdbmake を使わない python での変換スクリプトが含まれていた気がしたので探してみると python2 のコードでした。

import sys, re, io
import subprocess
import concurrent.futures
from pathlib import Path
from hashlib import md5

_source_enc = 'euc-jp'
_cdbmake = '/opt/local/bin/cdbmake'


def _genCdbFormat(target):
    re_commentline = re.compile("^;")
    re_keyvalue = re.compile("^([^ ]+) +(.+)$")
    fmt = "+{key_len},{val_len}:{key}->{val}"
    
    def _gen():
        try:
            while True:
                line = yield
                if not re_commentline.match(line):
                    matched = re_keyvalue.match(line)
                    if matched:
                        key = matched.group(1)
                        val = matched.group(2)
                        print(fmt.format(key=key, key_len=len(key.encode()),
                                         val=val, val_len=len(val.encode())),
                              file=target)
        finally:
            print('', file=target)

    gen = _gen()
    next(gen)
    return gen
    
        
def _runCdbMake(filename, buff):
    src_p = Path(filename)
    tar_p = src_p.parent / (src_p.name + '.cdb')
    tmp_name = md5(bytes(src_p.name, 'utf-8')).hexdigest()
    tmp_p = src_p.parent / tmp_name
    
    if tar_p.exists():
        return ('[Error: '+str(tar_p)+' already exists]', 1)

    done = subprocess.run([_cdbmake, str(tar_p), str(tmp_p)],
                          input=buff.getvalue(), text=True)
    return (str(tar_p), done.returncode)
    
    
def make(filename):
    with open(filename, "r", encoding=_source_enc) as source:
        with io.StringIO() as target:
            gen = _genCdbFormat(target)
            for line in source:
                gen.send(line)
            gen.close()
            return _runCdbMake(filename, target)


if __name__ == '__main__':
    with concurrent.futures.ProcessPoolExecutor() as pool:
        futures = {
            pool.submit(make, arg): arg
            for arg in sys.argv[1:]
        }

        for completed in concurrent.futures.as_completed(futures):
            print('%s -> %s, exit %d' % (futures[completed], *completed.result()))

(gist)