秀丸エディタで「行のユニーク化」:差分比較の前に“同一行の集合”にする(順序を捨てる)

差分比較(diff)って、こういう時に荒れる。

  • 行の順番が違うだけで全部差分に見える
  • 同じ行が何度も出てきて、差分が汚れる
  • 「結局、存在する行の集合は同じ?」を見たいだけなのに、順序が邪魔

そんな時に効くのが 行のユニーク化
つまり、テキストを「同一行の集合」にしてから比較する。

やることはこれだけ。

  1. 行を ソート
  2. 行を 重複排除(Unique)
  3. 必要なら 空行や行末空白も調整

これで diff は一気に読みやすくなる。


どんな時に使う?

  • 設定ファイルの値一覧を比較したい
  • 抽出したURL一覧、ホスト名一覧を比較したい
  • ログから拾った“エラー行一覧”の比較
  • 2つのファイルが「同じ要素を含むか」を確認したい(順序は不要)

方式(何を揃えるか)

“集合化”するなら、よくある揃え方は次の3つ。

A) そのまま集合化(最小)

  • ソート + 重複排除
  • 行末空白とか大小文字はそのまま

B) 大文字小文字を無視して集合化

  • ABCabc を同じ扱いにして比較したい時

C) 行末空白を消して集合化(おすすめ)

  • 見えない空白のせいで「別行」扱いになる事故を防ぐ

この記事の手順は、A/B/Cの切り替えができる形にする。


用意するもの(2ファイル)

  • PowerShell フィルタ:filters\hm_setify.ps1
  • 秀丸マクロ:line_setify.mac

外部コマンド連携(runex)で、選択(または全文)をフィルタへ渡して戻す方式。


1) PowerShell フィルタ(集合化の本体)

ファイル名:filters\hm_setify.ps1

param(
  [switch]$IgnoreCase,
  [switch]$TrimRight,
  [switch]$DropBlank
)

[Console]::InputEncoding  = [System.Text.UTF8Encoding]::new($false)
[Console]::OutputEncoding = [System.Text.UTF8Encoding]::new($false)

$text  = [Console]::In.ReadToEnd()
$lines = $text -split "`r?`n"

if ($TrimRight) {
  $lines = $lines | ForEach-Object { $_ -replace "[ \t]+$", "" }
}

if ($DropBlank) {
  $lines = $lines | Where-Object { $_ -ne "" }
}

# Sort-Object -Unique で集合化(順序は捨てる)
if ($IgnoreCase) {
  # 大文字小文字無視:ToLowerInvariantでキー化して保持(元行はそのままだとブレるので小文字側で統一)
  $items = foreach ($l in $lines) {
    [PSCustomObject]@{ raw=$l; key=$l.ToLowerInvariant() }
  }

  $out = $items |
    Sort-Object key -Unique |
    ForEach-Object { $_.key }   # 比較を安定させるため小文字で統一して出す
} else {
  $out = $lines | Sort-Object -Unique
}

$out -join "`r`n"

2) 秀丸マクロ(選択→集合化→戻す)

ファイル名:line_setify.mac

/*
  line_setify.mac
  行の集合化(ソート + 重複排除)を行う。
  - 目的:差分比較の前処理
*/

#ic   = val(input("大文字小文字無視: 0=しない / 1=する", "0"));
#trim = val(input("行末空白を削除: 0=しない / 1=する(推奨)", "1"));
#blank= val(input("空行を捨てる: 0=残す / 1=捨てる", "1"));

if (!selecting) {
  selectall;
}

$ps = "powershell.exe -NoProfile -ExecutionPolicy Bypass -File \"" + macrodir + "\\filters\\hm_setify.ps1\"";

if (#ic == 1)   { $ps = $ps + " -IgnoreCase"; }
if (#trim == 1) { $ps = $ps + " -TrimRight"; }
if (#blank == 1){ $ps = $ps + " -DropBlank"; }

// runex:選択→stdin、stdoutで置換
runex $ps
, 1
, 5, ""
, 6, ""
, 7, ""
, 1, ""
, 0
, 1
, 6   // UTF-8
, 1
;

if (!result) {
  message "失敗。filters\\hm_setify.ps1 の場所とPowerShell実行を確認。";
  endmacro;
}

message "行の集合化 完了";

導入手順(3分)

  1. マクロ置き場に filters フォルダを作る
  2. filters\hm_setify.ps1 を保存
  3. line_setify.mac を保存
  4. 秀丸で マクロ登録line_setify.mac
  5. 必要ならキー割り当て

使い方(差分比較の定番手順)

手順1:2つのファイルをそれぞれ集合化する

  • ファイルAを開く → マクロ実行 → 集合化
  • 別名保存(例:A.set.txt
  • ファイルBも同じ → 別名保存(例:B.set.txt

手順2:集合化したファイル同士をdiffする

  • A.set.txtB.set.txt を比較する

これで「順番が違うだけ」のノイズは消えて、
本当に差がある行だけが見える。


実例(イメージ)

元のテキスト(順序バラバラ+重複あり)

A:

cat
dog
cat
bird

B:

dog
bird
cat

集合化後(順序を捨てた同一行の集合)

A.set / B.set:

bird
cat
dog

diffすると差分はゼロ。
「含んでいる行の集合は同じ」ってことが一発で分かる。


注意点(ここだけ読めばOK)

  • 集合化は 順序を捨てる。ログの時系列みたいに順序が重要なら向かない
  • 大文字小文字無視をONにすると、出力は小文字に統一される(比較を安定させるため)
  • 行末空白は見えない差分の原因になりやすいので、基本は削除ONが無難
  • いきなり上書きしたくないなら、必ず別名保存してから比較する

まとめ

差分比較で「順番違い」がノイズになるなら、先に“集合化”する。
ソート+重複排除で、比較対象がスッキリして差分が読みやすくなる。

やることは単純だが、効果はデカい。

タイトルとURLをコピーしました