同じ行が何度も出てくるテキストは、見づらいし加工もしづらい。
やりたいのはだいたいこの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分)
- マクロ置き場に
filtersフォルダを作る filters\hm_uniq.ps1を保存dup_remove_lines.macを保存- 秀丸で マクロ登録(
dup_remove_lines.mac) - 必要ならキー割り当て
使い方
使い方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)」みたいな既製マクロもある。
“保持順あり/ソートして削除”の両方に対応してるタイプもあるので、好みで選ぶ。
