注意:此答案侧重于对 整个字符串 进行排序的一般情况(按 所有 个字符,而不仅仅是按 first em> 一个)。
您正在寻找 ordinal 排序,其中字符按 Unicode 代码点按数字排序( “ASCII 值”),因此 所有大写字母,作为一个组,排在所有小写字母之前。
从 Windows PowerShell v5.1 / PowerShell Core v7.0 开始,Sort-Object 总是使用词法排序[1 ](默认使用 invariant 区域性,但可以使用 -Culture 参数更改),其中 区分大小写的排序 仅表示 给定字母的小写形式直接在其大写形式之前,并非所有字母统称为;例如,b 在B 之前排序,但它们都在a 和A 之后(此外,逻辑与序数大小写相反,它是大写 字母第一):
PS> 'B', 'b', 'A', 'a' | Sort-Object -CaseSensitive
a
A
b
B
有一个解决方法,但是,它 (a) 将大写字母排在小写字母之前,并且 (b) 以牺牲性能为代价:
- 要通过直接序数排序获得更好的性能,您需要直接使用 .NET 框架 - 见下文,它还提供了一种先对小写字母进行排序的解决方案。
-
this GitHub issue 正在讨论增强
Sort-Object 以支持序数排序。
# PSv4+ syntax
# Note: Uppercase letters come first.
PS> 'B', 'b', 'A', 'a' |
Sort-Object { -join ([int[]] $_.ToCharArray()).ForEach('ToString', 'x4') }
A
B
a
b
解决方案将每个输入字符串映射到由 4 位十六进制组成的字符串。字符代码点的表示,例如'aB'变成'00610042',分别代表代码点0x61和0x42;比较这些表示就相当于按字符的代码点对字符串进行排序。
使用 .NET 进行直接、性能更好的序数排序:
# Get the last 50 lines as a list.
[Collections.Generic.List[string]] $lines = Get-Content -Tail 50 $filename
# Sort the list in place, using ordinal sorting
$lines.Sort([StringComparer]::Ordinal)
# Output the result.
# Note that uppercase letters come first.
$lines
[StringComparer]::Ordinal 返回一个实现[System.Collections.IComparer] 接口的对象。
在管道中使用此解决方案是可能的,但需要通过管道将行数组作为单个对象发送,-ReadCount 参数提供:
Get-Content -Tail 50 $filename -ReadCount 0 | ForEach-Object {
($lines = [Collections.Generic.List[string]] $_).Sort([StringComparer]::Ordinal)
$lines # output the sorted lines
}
注意:如上所述,这排序大写字母第一。
要对所有小写字母进行排序首先,您需要通过[System.Comparison[string]]委托实现自定义排序,这在PowerShell中可以被实现为一个脚本块({ ... }),它接受两个输入字符串并返回它们的排序等级(-1(或任何负值)代表小于,0代表等于,1(或任何正值)大于):
$lines.Sort({ param([string]$x, [string]$y)
# Determine the shorter of the two lengths.
$count = if ($x.Length -lt $y.Length) { $x.Length } else { $y.Length }
# Loop over all characters in corresponding positions.
for ($i = 0; $i -lt $count; ++$i) {
if ([char]::IsLower($x[$i]) -ne [char]::IsLower($y[$i])) {
# Sort all lowercase chars. before uppercase ones.
return (1, -1)[[char]::IsLower($x[$i])]
} elseif ($x[$i] -ne $y[$i]) { # compare code points (numerically)
return $x[$i] - $y[$i]
}
# So far the two strings compared equal, continue.
}
# The strings compared equal in all corresponding character positions,
# so the difference in length, if any, is the decider (longer strings sort
# after shorter ones).
return $x.Length - $y.Length
})
注意:对于 英文 文本,上述内容应该可以正常工作,但为了支持所有可能包含代理代码单元对和不同规范化形式(组合重音字符与分解重音字符)的 Unicode 文本,还需要做更多的工作。
[1] 在 Windows 上,默认执行所谓的单词排序:“某些非字母数字字符可能具有分配给它们的特殊权重。例如,连字符 (-) 可能分配给它的权重非常小,因此coop 和co-op 在排序列表中彼此相邻出现。";在 Unix 类平台上,字符串排序 是默认设置,其中没有特殊权重适用于非字母数字字符。 - 见the docs。