先に、答え。

CSVとして解析してから、delimiter="\t"のwriterで書き出します。カンマを一括でタブに置換すると、値の中のカンマまで変わるため使えません。

この記事の内容

対象・検証範囲:CPython 3.12.14 / Linux。掲載サンプルと期待する出力を照合。標準ライブラリのみ。

区切り文字の一括置換では足りない

"ノート, A5"という値には、区切りではないカンマがあります。CSVをテキストとして一括置換すると、この商品名まで変わってしまいます。

また「TSVなら引用符が不要」とも限りません。値にタブや改行があれば、区切りとデータを見分ける規則が必要です。この記事は、受け取り側も引用符を解釈する、CSVに似たタブ区切り形式を前提にします。

値を解析してから書き直す

次の例では、入力のカンマを保持し、値の中のタブも含めて往復確認します。ターミナルではタブが見えにくいため、表示だけ<TAB>へ置き換えています。保存すべき値はtsv_textです。

import csv
import io

source = 'id,name,note\n001,"ノート, A5","青\t太字"\n'
rows = list(csv.reader(io.StringIO(source, newline=""), strict=True))
if not rows or any(len(row) != len(rows[0]) for row in rows):
    raise ValueError("列数を確認してください")
output = io.StringIO(newline="")
writer = csv.writer(output, delimiter="\t", lineterminator="\n")
writer.writerows(rows)
tsv_text = output.getvalue()
print(tsv_text.replace("\t", "<TAB>"), end="")
restored = list(csv.reader(io.StringIO(tsv_text, newline=""), delimiter="\t"))
assert restored == rows
print("変換前後の値が一致")

期待する結果

id<TAB>name<TAB>note
001<TAB>ノート, A5<TAB>"青<TAB>太字"
変換前後の値が一致

「ノート, A5」のカンマは残ります。備考のタブは値の一部なので、そのフィールドは引用符で囲まれます。画面上の<TAB>は説明用の表示であり、TSVの正式な記号ではありません。

実ファイルでは入力をCSVとして読み、出力をnewline=""、文字コード指定付きで新しいファイルへ書き出します。CSVへ戻す場合は、読み込み側をタブ区切り、書き込み側をカンマ区切りにします。

連携先が引用符を理解しない場合

単純にタブで分割する取り込み先では、この形式を正しく読めないことがあります。その場合は「値の中のタブや改行を禁止する」「専用のエスケープを使う」など、相手の仕様が必要です。

値を空白へ置き換える方法もありますが、それは区切り形式の変換だけでなくデータの変更です。元データを保管し、どの文字が何に変わったかを確認できるようにしてください。仕様不明のまま引用符をすべて削除することは避けます。

確認と制限

このテストが保証するのは、Pythonのwriterが出したタブ区切りデータを、対応するreaderで読んだときの一致です。すべてのTSV利用ソフトでの互換性は検証していません。

手元のファイルに適用する前に、カンマ・タブ・引用符・改行を含む小さな例を実際の連携先へ取り込みます。文字化けが起きる場合は区切りの問題とは別なので、UTF-8とBOMの設定も確認します。大量データでは、この全件メモリー保持の例からストリーミング処理への変更が必要です。

参考にした公式資料

掲載サンプルは記載のPython環境で実行確認しています。すべてのOS・入力データを保証するものではありません。 編集・検証方針