Как сортировать по имени файла так же, как Windows Explorer?

Это известная проблема "ASCIIbetical" порядка и "естественного" порядка применительно к powershell. Чтобы иметь возможность сортировать в powershell так же, как это делает проводник, вы можете использовать эту оболочку через интерфейс StrCmpLogicalW, который фактически выполняет естественную сортировку для Windows Проводник. Это потребует некоторой сантехники.

Однако эта статья предполагает, что в python существует три реализации liner такого типа. Можно было бы надеяться, что командлет Get-ChildItem или, по крайней мере, поставщик файловой системы может иметь встроенную функцию естественной сортировки. К сожалению, они этого не делают.

Итак, вот вопрос, что является простейшей реализацией этого в Powershell? Простым я имею в виду наименьшее количество кода для записи и, возможно, сторонних/внешних скриптов/компонентов. В идеале я хочу короткую функцию Powershell, которая будет сортировать для меня.

2 ответа

Вот очень короткий код (только блок $ToNatural script), который выполняет трюк с регулярным выражением и оценщиком совпадений для заполнения чисел пробелами. Затем мы сортируем вход с заполненными числами как обычно и фактически получаем естественный порядок в результате.

$ToNatural = { [regex]::Replace($_, '\d+', { $args[0].Value.PadLeft(20) }) }
'----- test 1 ASCIIbetical order'
Get-Content list.txt | Sort-Object
'----- test 2 input with padded numbers'
Get-Content list.txt | %{ . $ToNatural }
'----- test 3 Natural order: sorted with padded numbers'
Get-Content list.txt | Sort-Object $ToNatural

Вывод:

----- test 1 ASCIIbetical order
1.txt
10.txt
3.txt
a10b1.txt
****.txt
a2b1.txt
a2b11.txt
a2b2.txt
b1.txt
b10.txt
b2.txt
----- test 2 input with padded numbers
 1.txt
 10.txt
 3.txt
a 10b 1.txt
a 1b 1.txt
a 2b 1.txt
a 2b 11.txt
a 2b 2.txt
b 1.txt
b 10.txt
b 2.txt
----- test 3 Natural order: sorted with padded numbers
1.txt
3.txt
10.txt
****.txt
a2b1.txt
a2b2.txt
a2b11.txt
a10b1.txt
b1.txt
b2.txt
b10.txt

И, наконец, мы используем этот однострочный файл для сортировки файлов по именам в натуральном порядке:

Get-ChildItem | Sort-Object { [regex]::Replace($_.Name, '\d+', { $args[0].Value.PadLeft(20) }) }

Вывод:

Directory: C:\TEMP\_110325_063356
Mode LastWriteTime Length Name 
---- ------------- ------ ---- 
-a--- 2011-03-25 06:34 8 1.txt 
-a--- 2011-03-25 06:34 8 3.txt 
-a--- 2011-03-25 06:34 8 10.txt 
-a--- 2011-03-25 06:34 8 ****.txt 
-a--- 2011-03-25 06:34 8 a2b1.txt 
-a--- 2011-03-25 06:34 8 a2b2.txt 
-a--- 2011-03-25 06:34 8 a2b11.txt 
-a--- 2011-03-25 06:34 8 a10b1.txt 
-a--- 2011-03-25 06:34 8 b1.txt 
-a--- 2011-03-25 06:34 8 b2.txt 
-a--- 2011-03-25 06:34 8 b10.txt 
-a--- 2011-03-25 04:54 99 list.txt 
-a--- 2011-03-25 06:05 346 sort-natural.ps1 
-a--- 2011-03-25 06:35 96 test.ps1


Перевод с python на PowerShell работает очень хорошо:

function sort-dir {
 param($dir)
 $toarray = {
 @($_.BaseName -split '(\d+)' | ?{$_} |
 % { if ([int]::TryParse($_,[ref]$null)) { [int]$_ } else { $_ } })
 }
 gci $dir | sort -Property $toarray
}
#try it
mkdir $env:TEMP\mytestsodir
1..10 + 100..105 | % { '' | Set-Content $env:TEMP\mytestsodir\$_.txt }
sort-dir $env:TEMP\mytestsodir
Remove-Item $env:TEMP\mytestsodir -Recurse

Вы можете сделать это еще лучше, если используете подход к функции прокси-сервера. Вы добавляете параметр -natur в Sort-Object, и у вас есть довольно красивое решение.

Обновление. Сначала я был совершенно удивлен тем, что PowerShell обрабатывает таким образом сопоставление массивов. После того, как я попытался создать тестовые файлы ("a0", "a100", "a2") + 1..10 + 100..105 | % { '' | Set-Content $env:TEMP\mytestsodir\$_.txt }, оказалось, что он не работает. Итак, я думаю, что нет элегантного решения, например, потому что PowerShell статичен под обложками, тогда как python является динамическим.

licensed under cc by-sa 3.0 with attribution.