# Sort

以字母, 数字或随机顺序排列变量的内容(可以选择是否移除重复项).

    SortedString := Sort(String , Options, Callback)

## 参数

String

  类型: 字符串

  需要排序的字符串.

Options

  类型: 字符串

  如果未设置或省略, String 按字母升序排序(不区分大小写), 使用换行符('n) 作为分隔符. 否则, 请指定从下面选项章节指定一个或多个选项的字符串(以任意顺序, 中间有可选的空格).

Callback

  类型: 函数对象

  如果未设置或省略, 将不执行自定义排序. 否则, 请指定要调用的比较列表中任意两个项的函数.

  回调接受三个参数, 并能定义如下:

      MyCallback(First, Second, Offset) { ...

  尽管为参数指定的名称并不重要, 但将依次为它们分配以下值:

  1. 第一个项目.
  2. 第二个项目.
  3. 在原始/未排序列表中看到的第二项与第一项的偏移量(以字符为单位)(参见示例)).

  如果不需要相应的信息, 你可以从回调参数列表的末尾省略一个或多个参数, 但在这种情况下, 必须指定星号作为最后一个参数, 例如, `MyCallback(Param1, *)`.

  当回调函数认为第一个参数大于第二个参数时, 它应该返回一个正整数; 当它认为这两个参数相等时, 它应该返回 0, "", 或什么都不返回; 否则, 它应该返回一个负整数. 如果返回值中存在小数点, 则忽略该部分(即 0.8 与 0 相同).

  回调函数使用与调用它的 Sort 函数相同的全局(或线程特定的) 设置.

  注意: 当指定 Callback 时, 除了 D, Z 和 U 之外的所有选项都会被忽略(尽管 N, C 和 CL 仍然会影响重复项的检测方式).

## 返回值

类型: 字符串

该函数返回指定字符串的排序版本.

## 选项

C, C1 或 COn: 区分大小写的排序(如果也存在 N 选项, 则此选项被忽略).

C0 或 COff: 不区分大小写的排序. 排序时大写字母 A-Z 被认为与其小写字母相同. 如果没有使用其他区分大小写的选项, 这是默认模式.

CL 或 CLocale: 基于当前用户区域设置的不区分大小写的排序. 例如, 大多数英语和西欧地区把字母 A-Z 和 ANSI 字母(如 Ä 和 Ü) 等同于它们的小写形式. 这种方法还使用了 "单词排序", 它以这样的方式(像 "coop" 和 "co-op" 这样的单词保持在一起) 处理连字符和撇号. 根据被排序项目的内容, 它的执行性能比默认的不区分方法差了 1 到 8 倍.

CLogical: 类似 CLocale, 但是字符串中的数字被认为是数字内容而不是文本. 例如, "A2" 被视为小于 "A10". 然而, 如果两个数字只因前导零的存在而不同, 有前导零的字符串可能被认为 小于 另一个字符串. 实际的行为在不同的操作系统版本中可能有所不同.

D x: 指定 x 作为分隔符, 它决定了每个项目的开始和结束位置. 分隔符总是区分大小写的. 如果此选项不存在, 则 x 默认为换行符(`n). 在大多数情况下, 即使是以 CR+LF(`r`n) 结尾的行也能工作, 但回车键(`r) 包含在比较中, 因此会影响排序顺序. 例如, `"B`r`nA"` 将按预期排序, 但 `"A`r`nA`t`r`nB"` 将把 `A`t`r` 放在 `A`r` 之前.

N: 数字排序. 每个项目都被假定为数字而不是字符串进行排序(例如, 如果此选项不存在, 则根据字母顺序字符串 233 被认为小于字符串 40). 十进制和十六进制字符串(例如 0xF1) 都被认为是数字. 不是以数字开头的字符串在排序中被看成是零. 把数字作为 64 位浮点值进行处理, 这样可以考虑到小数部分的每位数字(如果有).

P n: 根据字符位置 n(不使用十六进制的 n) 对项目进行排序(每个项目从第 n 个字符开始进行比较). 如果不使用该选项, n 默认为 1, 即第一个字符的位置. 排序会从第 n 个字符开始将每个字符串与其他字符串进行比较. 如果 n 大于任何字符串的长度, 则在排序时, 该字符串将被视为空白. 当与选项 n(数字排序) 一起使用时, 将使用字符串的字符位置, 这不一定与数字的数字位置相同.

R: 逆向排序(根据其他选项进行字母或数字排序).

Random: 随机排序. 此选项会使得除 D, Z 和 U 外的其他选项被忽略(尽管如此, 但 N, C 和 CL 仍会影响对于重复项的检测). 示例:

    MyVar := Sort(MyVar, "Random")
    MyVar := Sort(MyVar, "Random Z D|")

U: 移除列表中的重复项目使得每个项目都是唯一的. 如果 C 选项有效, 则项目的大小写必须匹配才会被认为是等同的. 如果 N 选项有效, 那么像 2 这样的项目将被认为是 2.0 的重复. 如果 P 或 \(反斜杠) 选项有效, 则整个项目必须相同才看成是重复项, 而不仅是用于排序的子字符串. 如果 Random 选项或自定义排序生效, 只有当排序结果中出现相邻的重复项时, 重复项才会被删除. 例如, 当 `"A|B|A"` 被随机排序时, 结果可能包含一个或两个 A.

Z: 要理解此选项, 请考虑内容为 `"RED`nGREEN`nBLUE`n"` 的变量. 如果不存在 Z 选项, 则最后的换行符(`n) 会被认为是最后那个项目的一部分, 因此变量中只有三个项目. 但如果指定了选项 Z, 则最后的 `n(如果存在) 将被认为分隔了列表最后的一个空项目, 因此变量中有四个项目(最后一个是空的).

\: 根据每个项目中最后的反斜杠后面的子字符串进行排序. 如果项目中不含有反斜杠, 则使用整个项目作为排序的子字符串. 此选项可用于排序单独的文件名称(即不包含路径), 例如在下面的例子中, 排序后 AAA.txt 行在 BBB.txt 行的上面, 因为在排序中它们的目录被忽略了:

    C:\BBB\AAA.txt
    C:\AAA\BBB.txt

注意: 当反斜杠选项存在时, N 和 P 选项会被忽略.

## 备注

这个函数通常用于对一个包含行列表的变量进行排序, 其中每行以换行符(`n) 结尾. 获取含有行列表的变量的一种方法是使用 FileRead 加载整个文件.

如果一个大的变量被排序后, 以后不再需要它的内容, 可以通过使其为空来释放它的内存, 例如 `MyVar := ""`.

## 相关

FileRead, File-reading loop, Parsing loop, StrSplit, CallbackCreate, A_Clipboard

## 示例

对以逗号分隔的数字列表进行排序.

    MyVar := "5,3,7,9,1,13,999,-4"
    MyVar := Sort(MyVar, "N D,")  ; 数值排序, 使用逗号作为分隔符.
    MsgBox MyVar   ; 结果为 -4,1,3,5,7,9,13,999

对文件的内容进行排序.

    Contents := FileRead("C:\Address List.txt")
    FileDelete "C:\Address List (alphabetical).txt"
    FileAppend Sort(Contents), "C:\Address List (alphabetical).txt"
    Contents := ""  ; 释放内存.

设置 `Win`+`C` 热键来从打开的资源管理器窗口中复制文件, 对其中的文件名进行排序后放回剪贴板.

    #c:: ; Win+C
    {
        A_Clipboard := "" ; 必须为空以检测是否有效.
        Send "^c"
        if !ClipWait(2)
            return
        MsgBox "Ready to be pasted:`n" Sort(A_Clipboard)
    }

演示通过回调函数进行自定义排序.

    MyVar := "This`nis`nan`nexample`nstring`nto`nbe`nsorted"
    MsgBox Sort(MyVar,, LengthSort)
    LengthSort(a1, a2, *)
    {
        a1 := StrLen(a1), a2 := StrLen(a2)
        return a1 > a2 ? 1 : a1 < a2 ? -1 : 0  ; 根据上面确定的长度进行排序.
    }

    MyVar := "5,3,7,9,1,13,999,-4"
    MsgBox Sort(MyVar, "D,", IntegerSort)
    IntegerSort(a1, a2, *)
    {
        return a1 - a2  ; 按升序数字排序. 只有当差值不会大到溢出有符号的 64 位整数时, 此方法才有效.
    }

    MyVar := "1,2,3,4"
    MsgBox Sort(MyVar, "D,", ReverseDirection)  ; 将列表反转, 使其包含 4,3,2,1
    ReverseDirection(a1, a2, offset)
    {
        return offset  ; 如果 a2 在原列表中 a1 之后, 则偏移量为正; 否则为负.
    }

    MyVar := "a bbb cc"
    ; 按升序排列; 使用胖箭头函数:
    MsgBox Sort(MyVar, "D ", (a,b,*) => StrLen(a) - StrLen(b))

dftg