秀丸エディタで「行のソート」:選択行を昇順/降順、数値/自然順も切り替える

行が並んでるテキストは、とにかくソートすると扱いやすくなる。

  • ファイル名の一覧
  • 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分)

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

使い方

選択行だけソートする(おすすめ)

  • ソートしたい行を選択
  • マクロ実行
  • 昇順/降順、方式(文字列/数値/自然順)を選ぶ

ファイル全体をソートする

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

注意点(ハマりやすい)

  • 数値ソートは「数値として解釈できない行」を最後に寄せる仕様
    (混在データならこの方が事故りにくい)
  • 自然順は簡易実装(数字の塊を0埋め)
    複雑なケース(桁が異常に長い、符号、少数、複数ブロック等)で要調整
  • 文字化けするなら encode=6(UTF-8)0(ANSI/Shift-JIS) に変えて試す

まとめ

  • ソートはテキスト加工の基本武器
  • 昇順/降順に加えて「数値」「自然順」があると実戦で困らない
  • 秀丸は選択範囲を外部に渡して戻せるので、こういう処理を簡単に増やせる
タイトルとURLをコピーしました