是否先用小写字母按字母顺序排序,然后再用大写字母排序? [英] Sort in alphabetical order with lowercase before uppercase?

查看:23
本文介绍了是否先用小写字母按字母顺序排序,然后再用大写字母排序?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我从古腾堡项目的"威廉·莎士比亚的威廉·莎士比亚全集"开始,这是http://www.gutenberg.org/ebooks/100提供的一个UTF-8文本文件。在PowerShell中,我运行

Get-Content -Tail 50 $filename | Sort-Object -CaseSensitive

我相信,它将文件的最后50行(即,由换行符分隔的字符串)通过管道传输到Sort-Object,它被配置为按字母顺序对以小写字母开头的字符串进行排序,然后再以大写字母开头。

为什么下图(尤其是P中)的输出没有按照-CaseSensitive开关排序?什么是解决方案?

推荐答案

注意:此答案侧重于整个字符串排序的一般情况(按所有字符排序,而不仅仅是按第一个字符排序)。

您正在寻找序号排序,其中字符按其Unicode代码点(";ASCII值";)进行数字排序,因此所有大写字母作为一个组,在所有小写字母之前对进行排序。

从Windows PowerShell V5.1/PowerShell Core V7.0开始,Sort-Object始终使用词汇排序[1](默认情况下使用不变的区域性,但可以使用-Culture参数更改),其中区分大小写的排序只表示小写形式例如,b排序在B之前,但它们都在aA之后(同时,逻辑从序数反转,其中大写字母排在前面):

PS> 'B', 'b', 'A', 'a' | Sort-Object -CaseSensitive
a
A
b
B

但是,有一个解决办法,它(A)将大写字母排在小写字母之前,(B)以牺牲性能为代价:

  • 为了通过直接顺序排序获得更好的性能,您需要直接使用.NET Framework-请参见下面的内容,该框架还提供了先对小写字母排序的解决方案。
  • 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',表示代码点0x610x42;然后,比较这些表示形式相当于按字符的代码点对字符串进行排序。


使用.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中可以将其实现为脚本挡路({ ... }),该脚本接受两个输入字符串并返回它们的排序排名(小于(或任何负值),0表示等于
$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上,默认情况下执行所谓的单词排序:可能会为某些非字母数字字符分配特殊权重。例如,可能为连字符(-)分配了非常小的权重,以便coopco-op在排序列表中相邻出现。";在类似Unix的平台上,字符串排序是默认设置,其中不会对非字母数字字符应用特殊权重。-请参阅the docs

这篇关于是否先用小写字母按字母顺序排序,然后再用大写字母排序?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆