Powershell - Sorting string objects with a special character
我在跑步
1 | 'S-tst','ssrst','srst2','s-zaa','s-a','s-zf' | Sort-Object |
我不应该得到回报吗
1 2 3 4 5 6 | s-a s-tst s-zaa s-zf srst2 ssrst |
但是我得到了以下信息:
1 2 3 4 5 6 | s-a srst2 ssrst S-tst s-zaa s-zf |
这怎么可能?排序对象在排序时只看字母吗?有没有办法用特殊的字符来分类?
这种行为是设计出来的,但并不总是人们想要/期望的。如果要用每个字符按ASCII顺序排序字符串,请使用以下命令:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 | Add-Type @" using System; using System.Collections; using System.Collections.Generic; using System.Globalization; public class SimpleStringComparer: IComparer, IComparer<string> { private static readonly CompareInfo compareInfo = CompareInfo.GetCompareInfo(CultureInfo.InvariantCulture.Name); public int Compare(object x, object y) { return Compare(x as string, y as string); } public int Compare(string x, string y) { return compareInfo.Compare(x, y, CompareOptions.OrdinalIgnoreCase); } public SimpleStringComparer() {} } "@ [string[]]$myList = 's-a','s-a1','s''a','s''a1', 'sa','sa1','s^a','S-a','S-a1','S''a','S''a1', 'Sa','Sa1','S^a' [System.Collections.Generic.List[string]]$list = [System.Collections.Generic.List[string]]::new() $list.AddRange($myList) [SimpleStringComparer]$comparer = [SimpleStringComparer]::new() $list.Sort([SimpleStringComparer]::new()) $list |
输出:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | s'a S'a s'a1 S'a1 s-a S-a s-a1 S-a1 sa Sa sa1 Sa1 s^a S^a |
更多信息
对于注释中的@tessellatingheckler,可以将字符串强制转换为char数组,从而按字符代码(序数)顺序对字符串进行排序。但是,它仍然以一种潜在的意外方式处理连字符和撇号(因为这些字符被忽略):
1 2 | $myList = 's-a','s-a1','s''a','s''a1', 'sa','sa1','s^a','S-a','S-a1','S''a','S''a1', 'Sa','Sa1','S^a' $myList | Sort-Object -Property { [char[]] $_ } |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | s'a S'a s-a S-a s'a1 S'a1 s-a1 S-a1 s^a S^a sa Sa sa1 Sa1 |
当前的排序行为是通过设计实现的。PowerShell似乎实现了"单词排序"。本文记录如下:https://msdn.microsoft.com/en-us/library/windows/desktop/dd318144(v=vs.85).aspx排序函数
除了忽略连字符和撇号(除了比较其他相同的字符串时),这种类型还将标点字符视为字母数字之前的字符,并处理重音字母及其对应字符。简单的演示如下:
1 |
要定义其他排序行为,目前您可能需要使用.NET,例如:
1 | Add-Type @" |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | using System; using System.Runtime.InteropServices; using System.Collections; public class NumericStringComparer: IComparer { //https://msdn.microsoft.com/en-us/library/windows/desktop/bb759947%28v=vs.85%29.aspx?f=255&MSPPError=-2147217396 [DllImport("shlwapi.dll")] public static extern int StrCmpLogicalW(string psz1, string psz2); public int Compare(object x, object y) { return Compare(x as string, y as string); } public int Compare(string x, string y) { return StrCmpLogicalW(x, y); } public NumericStringComparer() {} } |
1 2 3 4 5 | "@ [System.Collections.ArrayList]$myList = 's-a','s-a1','s''a','s''a1', 'sa','sa1','s^a','S-a','S-a1','S''a','S''a1', 'Sa','Sa1','S^a', , '100a','1a','001a','2a','20a' $myList.Sort([NumericStringComparer]::new()) $myList -join ', ' |
上面按照Windows资源管理器的方式对字符串进行排序(即,将前导数字视为数字值):
1 | s'a, s'a1, S'a, s-a, S-a, S-a1, S'a1, s-a1, S^a, s^a, 1a, 001a, 2a, Sa, Sa1, sa, sa1, 20a, 100a |
我已经提交了一个特性建议,以便在