Tei5’s Blog

Tei5 の メモ書き

TSV ファイルの整形 TSV2TXT.py ChatGPT4.0で生成

いわゆるTSVファイルのタブをスペースに置き換えて整形し直す。
自動処理の印刷用に使いたかった。

秀丸ではTSVの扱いが良いなと思ってる。
特に、「タブを含まない行はカラム幅の計算を無視する」というのがよい。
タイトルなどを入れておいてもフォーマットが崩れない。

同様の事をさせるPythonスクリプトを ChatGPT4.0に作らせた。

ほぼ ChatGPT 4.0 で生成できた。 ・タブがなければそのまま次へ。カラムの幅をカウントしない。のところに、不要な「print(line)」があって、 ・タブがなければそのまま出力するところの「print(line)」がなかったので、追加 と言うか、指示がまずかっただけかも。

もちろん、'/t' を ',' に変えれば、CSV2TXTにもなるはず。

import sys
import unicodedata

## ほぼ ChatGPT 4.0 で生成したスクリプト
## 秀丸のTSV表示と同様にタブをスペースに置き換えフォーマットし直す。全角も考慮する。
## 各カラムの最大幅を計算し出力するが、タブの無い行はそのまま出力する。
## カラムが数値のみの場合右寄せにする。

def get_display_width(s):
    width = 0
    for char in s:
        # W(全角)、F(全角)、A(アンビギュアス)の文字は2とカウント
        if unicodedata.east_asian_width(char) in 'WFA':
            width += 2
        else:
            width += 1
    return width

def format_tab_separated_values(input_lines):
    # カラムの最大幅を保存するリスト
    max_widths = []

    # 各行について
    for line in input_lines:
        # タブがなければそのまま出力
        if '\t' not in line:
            continue

        # タブで区切られた値を取得
        values = line.split('\t')

        # 新しいカラムが見つかった場合、max_widthsを拡張
        while len(max_widths) < len(values):
            max_widths.append(0)

        # 各カラムについて
        for i, value in enumerate(values):
            # カラムの現在の最大幅を更新
            max_widths[i] = max(max_widths[i], get_display_width(value))

    # 再度各行について
    for line in input_lines:
        # タブがなければそのまま出力
        if '\t' not in line:
            print(line)
            continue

        # タブで区切られた値を取得
        values = line.split('\t')

        # 各カラムを最大幅に合わせてフォーマット
        for i, value in enumerate(values):
            padding = ' ' * (max_widths[i] - get_display_width(value))
            # 数字のみなら右寄せ、それ以外は左寄せ
            if value.isdigit():
                print(padding + value, end=' ')
            else:
                # 最後のカラムは右詰めせずに出力
                if i == len(values) - 1:
                    print(value, end='')
                else:
                    print(value + padding, end=' ')

        print()

def main():
    lines = []
    for line in sys.stdin:
        lines.append(line.rstrip())

    format_tab_separated_values(lines)

if __name__ == "__main__":
    main()

使い方は、こんな感じ。

tsv2txt.py < org.tsv > format.txt

org.tsv

タイトルなど、この行にはタブは無し
名前  生年月日    住所  数値
山田 太郎   1990-01-15  東京都渋谷区  4567
John Smith  1985-07-03  New York, USA   123
田中 みな子    1995-12-28  大阪府大阪市  9876
Emily Johnson   1992-04-10  London, UK  2345
佐藤 健太   1988-09-22  東京都千代田区   56789

これを変換すると、

タイトルなど、この行にはタブは無し
名前          生年月日   住所           数値
山田 太郎     1990-01-15 東京都渋谷区    4567
John Smith    1985-07-03 New York, USA    123
田中 みな子   1995-12-28 大阪府大阪市    9876
Emily Johnson 1992-04-10 London, UK      2345
佐藤 健太     1988-09-22 東京都千代田区 56789

こんな感じに変換できる。