2011-03-25 28 views
27

這是着名的應用於PowerShell的「ASCIIbetical」順序與「自然」順序的問題。爲了能夠像瀏覽器一樣在PowerShell中進行排序,可以在StrCmpLogicalW API上使用this wrapper,這實際上是爲Windows資源管理器執行自然排序。這將需要一些管道。如何按照Windows資源管理器的相同方式按文件名進行排序?

但是,this article表明在Python中有三種班次的排序實現。人們會希望Get-ChildItem cmdlet或至少文件系統提供程序可以有內置的自然排序選項。不幸的是,他們沒有。

所以,這裏是一個問題,這是什麼在Powershell中最簡單的實現?簡單來說,我的意思是寫最少量的代碼,並且可能沒有第三方/外部腳本/組件。理想情況下,我想要一個短片 PowerShell功能,可以爲我排序。從蟒蛇的PowerShell

+0

多虧了一個有趣的問題,我只是試圖在PowerShell中使用正則表達式匹配評價。而且它確實有效!那麼我應該考慮其他應用程序。 – 2011-03-25 06:23:04

回答

52

下面是一些非常短的代碼(只是$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                            
+1

您可以將$ ToNatural腳本塊保存在您的個人資料中,然後只要您需要它就可以使用。 – JasonMArcher 2011-03-26 17:26:10

2

翻譯工作得很好:

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 function approach。您將-natur參數添加到Sort-Object,並且您擁有非常漂亮的解決方案。

更新:首先,我非常驚訝PowerShell以這種方式處理比較數組。在我試圖創建測試文件("a0", "a100", "a2") + 1..10 + 100..105 | % { '' | Set-Content $env:TEMP\mytestsodir\$_.txt }後,事實證明它不起作用。所以,我認爲沒有優雅的解決方案,因爲PowerShell在封面上是靜態的,而python是動態的。

0

允許我從另一個問題複製並粘貼我的答案。

Powershell Sort-Object Name with numbers doesn't properly

Windows資源管理器使用SHLWAPI.DLL遺留API排序字符串時叫StrCmpLogicalW,這就是我們看到不同的排序結果的原因。

我不想使用填充零方法,所以寫一個腳本。

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

由於我不是一個C#專家,所以拉請求讚賞。

查找下面的PowerShell腳本,它使用相同的API。

function Sort-Naturally 
{ 
    PARAM(
     [string[]]$strArray 
    ) 

    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()); 
     } 
    } 
} 
'@ 

    return [NaturalSort.NaturalSort]::Sort($strArray) 
} 

查找下面的測試結果。

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

而且,

PS> # Not good 
PS> $t = (ls .\Scripts*.txt).name 
PS> $t | Sort-Object 
Scripts1.txt 
Scripts10.txt 
Scripts2.txt 
PS> # Good 
PS> Sort-Naturally -strArray $t 
Scripts1.txt 
Scripts2.txt 
Scripts10.txt 
+0

與接受的答案相比,您能否給出答案的優點/缺點? – 2018-01-19 04:26:48

相關問題