xlogI125’s blog

パソコン作業を効率化したい

PowerShell練習 CSVファイルをStrCmpLogicalWの順で並べ替える

メモ

  • Import-Csv で取得した PSCustomObject の配列を List に変換
  • List.Sort(Comparer[PSCustomObject]) や List.Sort(Comparison<PSObject>) で PSCustomObject の NoteProperty の値を StrCmpLogicalW に渡して並べ替え
  • 並べ替えに使用する列名は決め打ち
    • CSVファイルにはあらかじめ並べ替え用の列を用意しておく

使い捨てスクリプト

  • powershell.exeのコンソールに右クリックで貼り付けて実行
# PowerShell 5.1, Windows 11

using namespace System.Collections.Generic

Set-StrictMode -Version Latest

Add-Type -Language CSharp -TypeDefinition @'
using System.Runtime.InteropServices;

namespace Win32Functions {
  public class Win32StrCmpLW {
    [DllImport(
      "Shlwapi.dll", CharSet = CharSet.Unicode, EntryPoint = "StrCmpLogicalW"
    )]
    public static extern int StrCmpLogicalW(
      [MarshalAs(UnmanagedType.LPWStr)] string psz1, 
      [MarshalAs(UnmanagedType.LPWStr)] string psz2
    );  
  }
}
'@

class MyComparer : Comparer[PSCustomObject] {
  [int]Compare([PSCustomObject]$x, [PSCustomObject]$y) {
    # あらかじめCSVファイルに並べ替え用の列名"SORT"を用意しておく
    $str1 = [string]$x.'SORT'
    $str2 = [string]$y.'SORT'
    return [Win32Functions.Win32StrCmpLW]::StrCmpLogicalW($str1, $str2);
  }
}

$a = Import-Csv -Encoding Default -Path "${env:USERPROFILE}\Desktop\test.csv"
$b = [List[PSCustomObject]]@($a)

$b.Sort([MyComparer]::new())

$b | ConvertTo-Csv -NoTypeInformation | Set-Clipboard
  • テスト用CSVデータの用意が難しい場合
  • List.Sort(Comparison<PSObject>)
# PowerShell 5.1, Windows 11

Set-StrictMode -Version Latest

$row0 = [PSCustomObject]@{sort = "0040A"; col1 = "1A"; col02 = "4B"}
$row1 = [PSCustomObject]@{sort = "02A";   col1 = "2A"; col02 = "2B"}
$row2 = [PSCustomObject]@{sort = "1A";    col1 = "3A"; col02 = "1B"}
$row3 = [PSCustomObject]@{sort = "30A";   col1 = "4A"; col02 = "3B"}
$a = @($row0, $row1, $row2, $row3)
$b = $a | ConvertTo-Csv -NoTypeInformation 
$c = $b | ConvertFrom-Csv

Add-Type -Language CSharp -TypeDefinition @'
using System.Collections.Generic;
using System.Management.Automation;
using System.Runtime.InteropServices;

namespace MyNamespace {
  public class MyClass {
    [DllImport(
      "Shlwapi.dll", CharSet = CharSet.Unicode, EntryPoint = "StrCmpLogicalW"
    )]
    public static extern int StrCmpLogicalW(
      [MarshalAs(UnmanagedType.LPWStr)] string psz1, 
      [MarshalAs(UnmanagedType.LPWStr)] string psz2
    );
    
    public static int MySortStrCmpLW(PSObject obj1, PSObject obj2) {
      string str1 = obj1.Properties[@"SORT"].Value.ToString();
      string str2 = obj2.Properties[@"SORT"].Value.ToString();
      return StrCmpLogicalW(str1, str2);
    }
    
    public static PSObject[] MySort(PSObject[] objs) {
      List<PSObject> tmp = new List<PSObject>(objs);
      tmp.Sort(MySortStrCmpLW);
      return tmp.ToArray();
    }
  
  }
}
'@

$d = [MyNamespace.MyClass]::MySort($c);

$d