プログラム 技術

PowerShellでCSVファイルからDiffを取る

同じ列内容で構成されている2つのCSVファイルからDiff(差分)をプログラムで取る必要があったので、その時のメモとなります

名称バージョン
PowerShell7.5.1

キーベースで比較

まずは特定の列を指定してDiffを取る方法となります

# ハッシュテーブルを作成
$hash1 = @{}
$hash2 = @{}

foreach ($row in $csv1) {
    $hash1[$row.$Key] = $row
}

foreach ($row in $csv2) {
    $hash2[$row.$Key] = $row
}

# ファイル1にのみ存在するレコード
foreach ($hash1key1 in $hash1.Keys) {
    if (-not $hash2.ContainsKey($hash1key1)) {
        $diffRow = $hash1[$hash1key1] | Select-Object *, @{Name='DiffType';Expression={'OnlyInFile1'}}, @{Name='ComparedFile';Expression={$FirstFile}}
        $diffResults += $diffRow
    }
}

# ファイル2にのみ存在するレコード
foreach ($hash2key1 in $hash2.Keys) {
    if (-not $hash1.ContainsKey($hash2key1)) {
        $diffRow = $hash2[$hash2key1] | Select-Object *, @{Name='DiffType';Expression={'OnlyInFile2'}}, @{Name='ComparedFile';Expression={$SecondFile}}
        $diffResults += $diffRow
    }
}

# 両方に存在するが内容が異なるレコード
foreach ($key in $hash1.Keys) {
    if ($hash2.ContainsKey($key)) {
        $row1 = $hash1[$key]
        $row2 = $hash2[$key]
        
        $isDifferent = $false
        $row1.PSObject.Properties | ForEach-Object {
            if ($_.Name -ne $Key -and $row1.($_.Name) -ne $row2.($_.Name)) {
                $isDifferent = $true
            }
        }
        
        if ($isDifferent) {
            $diffRow1 = $row1 | Select-Object *, @{Name='DiffType';Expression={'Modified_File1'}}, @{Name='ComparedFile';Expression={$FirstFile}}
            $diffRow2 = $row2 | Select-Object *, @{Name='DiffType';Expression={'Modified_File2'}}, @{Name='ComparedFile';Expression={$SecondFile}}
            $diffResults += $diffRow1
            $diffResults += $diffRow2
        }
    }
}

以下のCSVファイルをそれぞれ用意して『Name』列をキーとして実行した場合

# CSV1
ID,Name,Age,Department
1,田中太郎,30,営業部
2,佐藤花子,25,開発部
3,鈴木次郎,35,人事部
4,高橋三郎,28,営業部

# CSV2
ID,Name,Age,Department
1,田中太郎,31,営業部
2,佐藤花子,25,開発部
3,鈴木次郎,35,総務部
5,山田五郎,29,開発部

# 実行結果
"ID","Name","Age","Department","DiffType","ComparedFile"
"4","高橋三郎","28","営業部","OnlyInFile1",".\sample1.csv"
"5","山田五郎","29","開発部","OnlyInFile2",".\sample2.csv"
"1","田中太郎","30","営業部","Modified_File1",".\sample1.csv"
"1","田中太郎","31","営業部","Modified_File2",".\sample2.csv"
"3","鈴木次郎","35","人事部","Modified_File1",".\sample1.csv"
"3","鈴木次郎","35","総務部","Modified_File2",".\sample2.csv"

片方のCSVにしかないデータと両方にあるかつ、データの違いがあるものが出力されています

行番号ベースで比較

続いて行番号ベースで比較となります

$maxRows = [Math]::Max($csv1.Count, $csv2.Count)
            
for ($i = 0; $i -lt $maxRows; $i++) {
    $row1 = if ($i -lt $csv1.Count) { $csv1[$i] } else { $null }
    $row2 = if ($i -lt $csv2.Count) { $csv2[$i] } else { $null }
    
    if ($row1 -eq $null) {
        # ファイル2にのみ存在
        $diffRow = $row2 | Select-Object *, @{Name='RowNumber';Expression={$i+1}}, @{Name='DiffType';Expression={'OnlyInFile2'}}, @{Name='ComparedFile';Expression={$SecondFile}}
        $diffResults += $diffRow
    }
    elseif ($row2 -eq $null) {
        # ファイル1にのみ存在
        $diffRow = $row1 | Select-Object *, @{Name='RowNumber';Expression={$i+1}}, @{Name='DiffType';Expression={'OnlyInFile1'}}, @{Name='ComparedFile';Expression={$FirstFile}}
        $diffResults += $diffRow
    }
    else {
        # 両方に存在、内容を比較
        $isDifferent = $false
        $row1.PSObject.Properties | ForEach-Object {
            if ($row1.($_.Name) -ne $row2.($_.Name)) {
                $isDifferent = $true
            }
        }
        
        if ($isDifferent) {
            $diffRow1 = $row1 | Select-Object *, @{Name='RowNumber';Expression={$i+1}}, @{Name='DiffType';Expression={'Modified_File1'}}, @{Name='ComparedFile';Expression={$FirstFile}}
            $diffRow2 = $row2 | Select-Object *, @{Name='RowNumber';Expression={$i+1}}, @{Name='DiffType';Expression={'Modified_File2'}}, @{Name='ComparedFile';Expression={$SecondFile}}
            $diffResults += $diffRow1
            $diffResults += $diffRow2
        }
    }
}

以下のCSVファイルをそれぞれ用意して実行した場合

# CSV1
ID,Name,Age,Department
1,田中太郎,30,営業部
2,佐藤花子,25,開発部
3,鈴木次郎,35,人事部
4,高橋三郎,28,営業部

# CSV2
ID,Name,Age,Department
1,田中太郎,31,営業部
2,佐藤花子,25,開発部
3,鈴木次郎,35,総務部
5,山田五郎,29,開発部

# 実行結果
"ID","Name","Age","Department","RowNumber","DiffType","ComparedFile"
"1","田中太郎","30","営業部","1","Modified_File1",".\sample1.csv"
"1","田中太郎","31","営業部","1","Modified_File2",".\sample2.csv"
"3","鈴木次郎","35","人事部","3","Modified_File1",".\sample1.csv"
"3","鈴木次郎","35","総務部","3","Modified_File2",".\sample2.csv"
"4","高橋三郎","28","営業部","4","Modified_File1",".\sample1.csv"
"5","山田五郎","29","開発部","4","Modified_File2",".\sample2.csv"

先ほどと同じように片方のCSVにしかないデータと両方にあるかつ、データの違いがあるものが出力されています

最後に

これでPowerShellでCSVのDiffを出力することができます。次回はC#での実装について書こうと思います
また、今回紹介したPowerShellはいつものごとくGitHubにアップしていますので参考にしてみてください

GitHub
BlogSampleCodeProjects/CSVDiff_PowerShell at main · nasuton/BlogSampleCodeProjects · GitHub
BlogSampleCodeProjects/CSVDiff_PowerShell at main · nasuton/BlogSampleCodeProjects · GitHub

Project for sample code used in the blog.(Blogで記載しているサンプルコード ...

GitHubへ

会社紹介

私が所属しているアドバンスド・ソリューション株式会社(以下、ADS)は一緒に働く仲間を募集しています

会社概要
「技術」×「知恵」=顧客課題の解決・新しい価値の創造

この方程式の実現はADSが大切にしている考えで、技術を磨き続けるgeekさと、顧客を思うloveがあってこそ実現できる世界観だと思っています
この『love & geek』の精神さえあれば、得意不得意はno problem!
技術はピカイチだけど顧客折衝はちょっと苦手。OKです。技術はまだ未熟だけど顧客と知恵を出し合って要件定義するのは大好き。OKです
凸凹な社員の集まり、色んなカラーや柄の個性が集まっているからこそ、常に新しいソリューションが生まれています

ミッション
私たちは、テクノロジーを活用し、業務や事業の生産性向上と企業進化を支援します

ホームページ
アドバンスド・ソリューション株式会社|ADS Co., Ltd.
アドバンスド・ソリューション株式会社|ADS Co., Ltd.

Microsoft 365/SharePoint/Power Platform/Azure による DX コンサル・シス ...

サイトへ移動

PR

-プログラム, 技術
-