【Delphi】三井住友カードの利用明細 CSV を『やよいの青色申告』のスマート取引取込で取り込める形式に変換する

# はじめに

自営業だと確定申告が 2 月から始まります [^1]。1 月になったので [^2]、利用明細を『やよいの青色申告』へすべて取り込もうと思ったのですが、CSV の加工が必要だったのを忘れていました。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/21785/bcb26bbb-92a2-642f-7133-c7627dd81625.png)

三井住友カードの利用明細 CSV を『やよいの青色申告』のスマート取引で使えるようにするには、CSV に加工が必要なのです。

 - [CSV形式のクレジットカードの利用明細を取り込む (弥生)](https://support.yayoi-kk.co.jp/subcontents.html?page_id=25756)

# 変換

具体的には、次のような CSV を

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/21785/25dfdc4c-0b8c-6748-49b1-486d0f57f95d.png)

このように変換する必要があります。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/21785/7722fd6d-ea4e-97cf-ef2d-27d58c9f7206.png)

 - ヘッダ行を削除
 - 合計行を削除
 - F 列と G 列の間に列を追加する
 - 金額がマイナスの場合はプラスにして新しく追加した列に移動

### ヘッダ

スマート取引取込を行う際、本来ヘッダ行はあっても取り込めるのですが、オリジナルの CSV のヘッダ行は<font color="crimson">フィールドのヘッダではない</font>ので、取り込もうとすると次のようなエラーが出てしまいます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/21785/d100fb64-13a5-1c19-473a-463d8e3dbea7.png)

このため、ヘッダ行 (先頭行) を削除しています。

## ソースコード

ソースコードは以下の通りです。

```pascal:ModCSV.dpr
{
  三井住友カードの利用明細 CSV を
  『やよいの青色申告』のスマート取引取込で取り込める形式に変換する
}
program ModCSV;
{$APPTYPE CONSOLE}
{$R *.res}

uses
  System.SysUtils,
  System.Classes,
  System.IOUtils;

var
  SrcDir, DstDir: string;
begin
  if ParamCount > 0 then
    SrcDir := ParamStr(1)
  else
    SrcDir := TPath.GetDirectoryName(ParamStr(0));
  if ParamCount > 1 then
    DstDir := ParamStr(2)
  else
    DstDir := '.\conv';
  TDirectory.CreateDirectory(DstDir);
  var CSV := TStringList.Create;
  var Lines := TStringList.Create;
  var Fields := TStringList.Create;
  try
    Fields.StrictDelimiter := True;
    var CSVFiles := TDirectory.GetFiles(SrcDir, '*.csv');
    for var FileName in CSVFiles do
    begin
      CSV.Clear;
      Lines.LoadFromFile(FileName);
      { 先頭行はヘッダ、最終行は合計金額なので除外 }
      for var l := 1 to Lines.Count - 2 do
      begin
        Fields.DelimitedText := Lines[l];
        Fields.Insert(Fields.Count - 1, ''); // 空白のフィールドを追加
        var v := StrToIntDef(Fields[5], 0);
        if v < 0 then
        begin
          Fields[5] := '';
          Fields[6] := IntToStr(-v);
        end;
        CSV.Add(Fields.DelimitedText);
      end;
      CSV.SaveToFile(TPath.Combine(DstDir, TPath.GetFileName(FileName)));
    end;
  finally
    Lines.Free;
    Fields.Free;
    CSV.Free;
  end;
end.
```

Delphi 12 Athens でコンパイル可能です。もちろん無償版の Community Edition でも大丈夫です。このファイルを開いてコンパイルすると `ModCSV.exe` ができます。

### DelimitedText / CommaText

DelimitedText や CommaText はメソッドではなくプロパティです。カンマ区切り文字列をリストに展開したり (Write)、逆にリストをカンマ区切り文字列にする (Read) 事もできます。

 - [System.Classes.TStrings.DelimitedText (DocWiki)](https://docwiki.embarcadero.com/Libraries/ja/System.Classes.TStrings.DelimitedText)
 - [System.Classes.TStrings.CommaText (DocWiki)](https://docwiki.embarcadero.com/Libraries/ja/System.Classes.TStrings.CommaText)

## 使い方

変換したい CSV があるフォルダに `ModCSV.exe` をコピーして実行するだけです。変換されたファイルはサブフォルダ `conv` に格納されます。

```
ModCSV [変換したい CSV のあるフォルダ [変換した CSV を格納するフォルダ]] 
```

コマンドラインパラメータで変換元と変換先のフォルダを指定する事もできます。

# おわりに

こういうのは機械的にやった方がミスも少ないですよね。複数月の CSV を処理するとなると、どうしても加工ミスや加工漏れが出てきますし。

**See also:**

 - [Delphi 10.3 Rio で CSV を処理する (Qiita)](https://qiita.com/ht_deko/items/2802677fe1cfaa4d1332)

[^1]: 2025 年 (令和 6 年分) の確定申告は 2/17～3/17 です。
[^2]: 12 月利用分は 1 月請求分で確定する。2 月になる事はまずないかなぁ...いずれにせよ、手入力は嫌なのじゃ。