行が並んでるテキストは、とにかくソートすると扱いやすくなる。
- ファイル名の一覧
- IDや番号の一覧
- 設定値の一覧
- 抽出したログの行
ただの昇順/降順だけじゃなく、実戦ではこういうのが要る。
- 数値ソート(2, 10, 100 の順にしたい)
- 自然順ソート(file2, file10 を“人間の感覚”で並べたい)
- 保持したい範囲だけ(選択した行だけソート)
この記事では「選択範囲(無ければカーソル行)」をソートするマクロを作る。
ソート方式も選べる。
できること
- 選択行をソート(選択が無ければカーソル行=実質何もしないので、基本は選択して使う)
- 昇順/降順
- ソート方式
- 文字列(通常)
- 数値
- 自然順(file2 < file10)
ソート方式の違い(例)
文字列(通常)
file1
file10
file2
自然順
file1
file2
file10
数値
2
10
100
方式の選び方(目安)
- 数値ソート:行が「数字だけ」または先頭が数字
- 自然順:
A2,A10,file9みたいに数字が混じる - 文字列:単純な辞書順でいい
用意するもの(2ファイル)
- PowerShell フィルタ:
filters\hm_sort.ps1 - 秀丸マクロ:
line_sort.mac
外部コマンド連携(runex)で、選択をPowerShellに渡して結果を戻す方式。
1) PowerShell フィルタ(ソート本体)
ファイル名:filters\hm_sort.ps1
param(
[ValidateSet("str","num","nat")]
[string]$Mode = "str",
[ValidateSet("asc","desc")]
[string]$Order = "asc",
[switch]$IgnoreCase
)
[Console]::InputEncoding = [System.Text.UTF8Encoding]::new($false)
[Console]::OutputEncoding = [System.Text.UTF8Encoding]::new($false)
$text = [Console]::In.ReadToEnd()
$lines = $text -split "`r?`n"
# splitの都合で末尾に空要素が出ることがあるので、そのまま行として扱う。
# 空行をソートに含めたくないなら、ここでWhere-Objectで除外する。
# 文字列比較(大文字小文字)
$cmp = if ($IgnoreCase) { [StringComparer]::OrdinalIgnoreCase } else { [StringComparer]::Ordinal }
function Get-NatKey([string]$s) {
# 自然順用:数字の連続を 0埋めして比較キーにする(簡易)
# 例: "file2" -> "file0000000002"
# 桁は10固定。必要なら増やせる。
return ($s -replace '\d+', { param($m) $m.Value.PadLeft(10,'0') })
}
if ($Mode -eq "num") {
# 数値ソート:先頭の数値をdoubleで取る。取れない行は最後へ寄せる。
$items = foreach ($l in $lines) {
$n = $null
if ([double]::TryParse($l, [ref]$n)) {
[PSCustomObject]@{ line=$l; key=$n; ok=$true }
} else {
[PSCustomObject]@{ line=$l; key=0.0; ok=$false }
}
}
if ($Order -eq "asc") {
$sorted = $items | Sort-Object @{Expression="ok"; Ascending=$false}, @{Expression="key"; Ascending=$true}, @{Expression="line"; Ascending=$true}
} else {
$sorted = $items | Sort-Object @{Expression="ok"; Ascending=$false}, @{Expression="key"; Ascending=$false}, @{Expression="line"; Ascending=$true}
}
$out = $sorted | ForEach-Object { $_.line }
}
elseif ($Mode -eq "nat") {
# 自然順:比較キーを作ってソート
$items = foreach ($l in $lines) {
[PSCustomObject]@{ line=$l; key=(Get-NatKey $l) }
}
if ($IgnoreCase) {
if ($Order -eq "asc") {
$out = $items | Sort-Object @{Expression="key"; Ascending=$true}, @{Expression="line"; Ascending=$true} |
ForEach-Object { $_.line }
} else {
$out = $items | Sort-Object @{Expression="key"; Ascending=$false}, @{Expression="line"; Ascending=$true} |
ForEach-Object { $_.line }
}
} else {
if ($Order -eq "asc") {
$out = $items | Sort-Object @{Expression="key"; Ascending=$true}, @{Expression="line"; Ascending=$true} |
ForEach-Object { $_.line }
} else {
$out = $items | Sort-Object @{Expression="key"; Ascending=$false}, @{Expression="line"; Ascending=$true} |
ForEach-Object { $_.line }
}
}
}
else {
# 文字列:Ordinal(バイト順)で揃えたいので、キーをそのままに寄せる
# PowerShellのSort-Objectはカルチャ依存になり得るので、比較キーを作って寄せる(簡易)
$items = foreach ($l in $lines) {
$k = $l
if ($IgnoreCase) { $k = $l.ToLowerInvariant() }
[PSCustomObject]@{ line=$l; key=$k }
}
if ($Order -eq "asc") {
$out = $items | Sort-Object @{Expression="key"; Ascending=$true}, @{Expression="line"; Ascending=$true} |
ForEach-Object { $_.line }
} else {
$out = $items | Sort-Object @{Expression="key"; Ascending=$false}, @{Expression="line"; Ascending=$true} |
ForEach-Object { $_.line }
}
}
$out -join "`r`n"
2) 秀丸マクロ(選択→ソート→戻す)
ファイル名:line_sort.mac
/*
line_sort.mac
選択行(無ければ全文)をソートする。
- 昇順/降順
- 文字列/数値/自然順
*/
#order = val(input("並び: 1=昇順 / 2=降順", "1"));
#mode = val(input("方式: 1=文字列 / 2=数値 / 3=自然順", "1"));
#ic = val(input("大文字小文字無視: 0=しない / 1=する", "1"));
if (!selecting) {
selectall;
}
$ps = "powershell.exe -NoProfile -ExecutionPolicy Bypass -File \"" + macrodir + "\\filters\\hm_sort.ps1\"";
if (#mode == 2) {
$ps = $ps + " -Mode num";
} else if (#mode == 3) {
$ps = $ps + " -Mode nat";
} else {
$ps = $ps + " -Mode str";
}
if (#order == 2) {
$ps = $ps + " -Order desc";
} else {
$ps = $ps + " -Order asc";
}
if (#ic == 1) {
$ps = $ps + " -IgnoreCase";
}
// runex:選択→stdin、stdoutで置換
runex $ps
, 1
, 5, ""
, 6, ""
, 7, ""
, 1, ""
, 0
, 1
, 6 // UTF-8
, 1
;
if (!result) {
message "失敗。filters\\hm_sort.ps1 の場所とPowerShell実行を確認。";
endmacro;
}
message "行ソート 完了";
導入手順(3分)
- マクロ置き場に
filtersフォルダを作る filters\hm_sort.ps1を保存line_sort.macを保存- 秀丸で マクロ登録(
line_sort.mac) - 必要ならキー割り当て
使い方
選択行だけソートする(おすすめ)
- ソートしたい行を選択
- マクロ実行
- 昇順/降順、方式(文字列/数値/自然順)を選ぶ
ファイル全体をソートする
- 選択せずにマクロ実行(自動で全文を対象)
注意点(ハマりやすい)
- 数値ソートは「数値として解釈できない行」を最後に寄せる仕様
(混在データならこの方が事故りにくい) - 自然順は簡易実装(数字の塊を0埋め)
複雑なケース(桁が異常に長い、符号、少数、複数ブロック等)で要調整 - 文字化けするなら
encode=6(UTF-8)を0(ANSI/Shift-JIS)に変えて試す
まとめ
- ソートはテキスト加工の基本武器
- 昇順/降順に加えて「数値」「自然順」があると実戦で困らない
- 秀丸は選択範囲を外部に渡して戻せるので、こういう処理を簡単に増やせる
