秀丸エディタで「重複行の削除」:保持順のまま/ソートしてから(バックアップ前提)

同じ行が何度も出てくるテキストは、見づらいし加工もしづらい。
やりたいのはだいたいこの2つ。

  • 保持順あり:最初に出てきた順番を守って、重複だけ消す(“初出だけ残す”)
  • ソートしてから:並べ替えて、重複をまとめて消す(順番は変わる)

この記事は、秀丸マクロ+PowerShellを使って「選択範囲 or 全体」を一発で重複削除する手順。


先に注意(大事)

一括で内容が変わる。まずは対象ファイルのコピーを作るか、バックアップを取ってからやる。


方式の違い(どっちを使う?)

A) 保持順あり(順番を守る)

  • メリット:元の並びがそのまま
  • デメリット:大量行だとソートより遅い場合がある
  • 例:ログ、メモ、URL一覧、抽出結果(順番に意味があるやつ)

B) ソートしてから(順番は変わる)

  • メリット:速い・同じものがまとまって見やすい
  • デメリット:元の順番は壊れる
  • 例:辞書、ID一覧、重複排除した“集合”が欲しいだけ

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

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

filters フォルダは、マクロと同じ場所に作る想定。


1) PowerShell フィルタ(重複削除の本体)

ファイル名:filters\hm_uniq.ps1

param(
  [ValidateSet("keep","sort")]
  [string]$Mode = "keep",

  [switch]$IgnoreCase
)

# UTF-8で入出力を固定(文字化けしたらマクロ側のencodeも調整)
[Console]::InputEncoding  = [System.Text.UTF8Encoding]::new($false)
[Console]::OutputEncoding = [System.Text.UTF8Encoding]::new($false)

$text = [Console]::In.ReadToEnd()

# 行分割(CRLF/LF混在でもOK)
$lines = $text -split "`r?`n"

# 末尾が改行で終わってた場合、splitで最後に空要素が入ることがある
# ここでは「空行」も通常の行として扱う(空行が複数あれば1行にまとまる)
# 空行を全部残したいなら、このスクリプトは使わず別仕様にする必要あり

if ($IgnoreCase) {
  if ($Mode -eq "sort") {
    $out = $lines | Sort-Object -Unique
  } else {
    $seen = New-Object 'System.Collections.Generic.HashSet[string]' ([StringComparer]::OrdinalIgnoreCase)
    $buf  = New-Object 'System.Collections.Generic.List[string]'
    foreach ($l in $lines) {
      if ($seen.Add($l)) { [void]$buf.Add($l) }
    }
    $out = $buf
  }
} else {
  if ($Mode -eq "sort") {
    $out = $lines | Sort-Object -Unique
  } else {
    $seen = New-Object 'System.Collections.Generic.HashSet[string]'
    $buf  = New-Object 'System.Collections.Generic.List[string]'
    foreach ($l in $lines) {
      if ($seen.Add($l)) { [void]$buf.Add($l) }
    }
    $out = $buf
  }
}

# CRLFで返す(Windowsで無難)
$out -join "`r`n"

2) 秀丸マクロ(選択→フィルタ→置換)

ファイル名:dup_remove_lines.mac

/*
  dup_remove_lines.mac
  - 選択範囲があれば選択だけ
  - 選択がなければ全文
  - PowerShellフィルタに渡して stdout を選択範囲に戻す
*/

#mode = val(input("重複削除モード: 1=保持順(初出だけ残す) / 2=ソートして重複削除", "1"));
#ic   = val(input("大文字小文字無視: 0=しない / 1=する", "0"));

if (!selecting) {
  selectall;
}

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

if (#mode == 2) {
  $ps = $ps + " -Mode sort";
} else {
  $ps = $ps + " -Mode keep";
}

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

// runex:選択を stdin に流して、stdoutで選択を置換
// encode=6 (UTF-8) を使用。文字化けするなら 0(ANSI/Shift-JIS) に変更して試す。
runex $ps
, 1        // sync: 1=同期
, 5, ""    // stdin: 5=選択範囲
, 6, ""    // stdout: 6=選択範囲を置換
, 7, ""    // stderr: 7=出力枠へ
, 1, ""    // folder: 1=カレント
, 0        // show
, 1        // draw
, 6        // encode: 6=UTF-8 (0=ANSI)
, 1        // extended flags: 1=%解釈抑制
;

if (!result) {
  message "失敗。PowerShellのパス、filters\\hm_uniq.ps1 の場所、実行権限を確認。";
  endmacro;
}

message "重複行の削除 完了";

導入手順(3分)

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

使い方

使い方1:選択範囲だけ重複削除

  • 重複を消したい範囲を選択
  • マクロ実行
  • 1=保持順 or 2=ソート を選ぶ

使い方2:ファイル全体を重複削除

  • 選択せずにマクロ実行(自動で全文対象)

動作例

保持順(初出だけ残す)

入力:

A
B
A
C
B

出力:

A
B
C

ソートして重複削除

入力:

B
A
C
A
B

出力(順番が変わる):

A
B
C

よくあるハマりどころ

  • 空行:この仕様だと「空行も1行として扱う」ので、空行が大量にあると1行にまとまる
  • 末尾スペース"A""A " は別行扱い(見た目は似てても別)
  • 文字化け:マクロの encode=6(UTF-8)で崩れるなら、encode=0 を試す
  • 処理前の保険:ファイルをコピーしてから実行すると事故が軽い

代替:既製マクロを使う(自作が要らない)

「重複行を削除する簡易マクロ(EraseSameLine)」みたいな既製マクロもある。
“保持順あり/ソートして削除”の両方に対応してるタイプもあるので、好みで選ぶ。

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