programing

Windows 탐색기와 동일하게 파일 이름별로 정렬하는 방법은 무엇입니까?

powerit 2023. 9. 10. 12:41
반응형

Windows 탐색기와 동일하게 파일 이름별로 정렬하는 방법은 무엇입니까?

이것은 파워셸에 적용되는 "ASCIbetical" order 대 "Natural" order의 유명한 문제입니다.탐색기와 동일한 방식으로 파워셸을 정렬할 수 있도록 하려면 StrCmpLogicalW API를 통해 이 래퍼를 사용하면 되는데, 이 래퍼는 실제로 Windows 탐색기의 자연 정렬을 수행합니다.하지만 이것은 배관 작업이 좀 필요할 것입니다.

그러나 이 기사는 파이썬에 세 개의 라이너(liner)가 구현되어 있음을 시사합니다.Get-ChildItem cmdlet 또는 최소한 파일 시스템 공급자가 내장된 자연 정렬 옵션을 가질 수 있기를 바랍니다.안타깝게도, 그들은 그렇지 않습니다.

그렇다면 여기 질문이 있습니다. 파워셸에서 가장 간단하게 구현할 수 있는 것은 무엇일까요?간단히 말하자면, 써드파티/외부 스크립트/구성요소가 없을 수도 있고, 최소한의 코드를 쓰는 것을 의미합니다.이상적으로 나는 나를 위해 분류를 할 수 있는 짧은 파워셸 기능을 원합니다.

TL;DR

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

여기 아주 짧은 코드가 있습니다.$ToNatural스크립트 블록)을 사용하여 정규식과 일치 평가자를 사용하여 숫자에 공백을 추가합니다.그런 다음 평소와 같이 패딩된 숫자로 입력을 분류하고 결과적으로 자연스러운 순서를 얻습니다.

$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
a1b1.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
a1b1.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 a1b1.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                                                                                                              

다른 질문에 대한 답변을 복사해서 붙여넣을 수 있게 해주세요.

숫자가 있는 Powershell Sort-Object Name이(가) 제대로 되지 않음

윈도우 탐색기가 shlwapi.dll의 레거시 API를 사용하고 있습니다.StrCmpLogicalW, 그것이 다른 분류 결과를 보는 이유입니다.

저는 0을 패딩하고 싶지 않아서 대본을 썼습니다.

https://github.com/LarrysGIT/Powershell-Natural-sort

저는 C# 전문가가 아니기 때문에 깔끔하지 않으면 pull request를 해주시면 감사하겠습니다.

동일한 API를 사용하는 PowerShell 스크립트를 찾습니다.

function Sort-Naturally
{
    PARAM(
        [System.Collections.ArrayList]$Array,
        [switch]$Descending
    )

    Add-Type -TypeDefinition @'
using System;
using System.Collections;
using System.Collections.Generic;
using System.Runtime.InteropServices;
namespace NaturalSort {
    public static class NaturalSort
    {
        [DllImport("shlwapi.dll", CharSet = CharSet.Unicode)]
        public static extern int StrCmpLogicalW(string psz1, string psz2);
        public static System.Collections.ArrayList Sort(System.Collections.ArrayList foo)
        {
            foo.Sort(new NaturalStringComparer());
            return foo;
        }
    }
    public class NaturalStringComparer : IComparer
    {
        public int Compare(object x, object y)
        {
            return NaturalSort.StrCmpLogicalW(x.ToString(), y.ToString());
        }
    }
}
'@
    $Array.Sort((New-Object NaturalSort.NaturalStringComparer))
    if($Descending)
    {
        $Array.Reverse()
    }
    return $Array
}

테스트 결과는 아래와 같습니다.

PS> # Natural sort
PS> . .\NaturalSort.ps1
PS> Sort-Naturally -Array @('2', '1', '11')
1
2
11
PS> # If regular sort is being used
PS> @('2', '1', '11') | Sort-Object
1
11
2

PS> # Not good
PS> $t = ls .\testfiles\*.txt
PS> $t | Sort-Object
1.txt
10.txt
2.txt

PS> # Good
PS> Sort-Naturally -Array $t
1.txt
2.txt
10.txt

저는 @Larry Song의 답변을 선호합니다. 왜냐하면 그것은 윈도우 탐색기가 하는 것과 정확하게 정렬되기 때문입니다.저는 그것을 조금 더 쉽게 하기 위해 그것을 단순화하려고 노력했습니다.

Add-Type -TypeDefinition @"
using System.Runtime.InteropServices;
public static class NaturalSort
{
    [DllImport("Shlwapi.dll", CharSet = CharSet.Unicode)]
    private static extern int StrCmpLogicalW(string psz1, string psz2);
    public static string[] Sort(string[] array)
    {
        System.Array.Sort(array, (psz1, psz2) => StrCmpLogicalW(psz1, psz2));
        return array;
    }
}
"@

그러면 다음과 같이 사용할 수 있습니다.

$array = ('1.jpg', '10.jpg', '2.jpg')
[NaturalSort]::Sort($array)

출력:

1.jpg
2.jpg
10.jpg

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

Proxy 기능 접근법을 사용하면 훨씬 더 잘 할 수 있습니다.당신이 추가합니다.-natur에 매개 변수를 지정합니다.Sort-Object그리고 당신은 꽤 아름다운 해결책을 가지고 있습니다.

업데이트: 먼저 PowerShell이 어레이 비교를 이러한 방식으로 처리한다는 사실에 매우 놀랐습니다.테스트 파일을 만들고 난 후에("a0", "a100", "a2") + 1..10 + 100..105 | % { '' | Set-Content $env:TEMP\mytestsodir\$_.txt }되는 이 났거든요,이 으로 으로 이 .그래서 파워쉘은 커버 아래에서 정적인 반면 파이썬은 동적이기 때문에 이와 같은 우아한 솔루션은 없다고 생각합니다.

언급URL : https://stackoverflow.com/questions/5427506/how-to-sort-by-file-name-the-same-way-windows-explorer-does

반응형