SciTE 排序选择工具:带有前导空格的数字未按预期排序

SciTE sort selection tool : numbers with leading spaces are not sorted as expected

SciTE 编辑器带有嵌入式 Lua 脚本引擎,可以访问编辑器的文本缓冲区。这使得使用在 Lua 中编程并从工具菜单启动的工具扩展 SciTE 的功能成为可能。可从此处获得此类工具之一:

http://lua-users.org/wiki/SciteSortSelection

是一种按字母顺序对所选行进行排序的工具。 令我恼火的是 was/is 它不会按数字顺序对包含数字的行进行排序,而是像这样:

    1
  111
    2
  222
    3
  333

我希望的地方:

    1
    2
    3
  111
  222
  333

Google 和 Co. 在这里没有太大帮助,因为据我所知,还没有在线解决此问题的方法。查找和深入理解 table.sort() 的 Lua 文档也不是那么容易。因此,知识渊博的 Lua 程序员的问题是,修补现有 Lua 脚本代码的最佳方法是什么,以便数字(以及在前导空格的情况下带有文本的行)被排序为符合预期并且此任务的 Lua 代码运行得如此之快,以至于即使对大文件(50 MByte 或更多)进行排序也不会花费太多时间?

你的期望是错误的。你说算法应该按字母顺序对文本进行排序,而这正是它所做的。

因为Lua“11”小于“2”。 我想你会同意 "aa" 应该出现在 "b" 之前,这几乎是一回事。

如果您想更改文本的排序方式,您必须提供自己的函数。

Lua 参考手册说:

table.sort (list [, comp])

Sorts list elements in a given order, in-place, from list[1] to list[#list]. If comp is given, then it must be a function that receives two list elements and returns true when the first element must come before the second in the final order (so that, after the sort, i < j implies not comp(list[j],list[i])). If comp is not given, then the standard Lua operator < is used instead.

Note that the comp function must define a strict partial order over the elements in the list; that is, it must be asymmetric and transitive. Otherwise, no valid sort may be possible.

The sort algorithm is not stable: elements considered equal by the given order may have their relative positions changed by the sort.

因此您可以自由实现自己的 comp 函数来更改排序。

默认情况下table.sort(list) 以升序排列列表。 要使其按降序排序,请调用:

table.sort(list, function(a,b) return a > b end)

如果你想以不同的方式对待数字,你可以这样做:

t = {"111", "11", "3", "2", "a", "b"}

local function myCompare(a,b)
    local a_number = tonumber(a)
    local b_number = tonumber(b)
    if a_number and b_number then
       return a_number < b_number
    end
end

table.sort(t, myCompare)

for i,v in ipairs(t) do
    print(v)
end

这会给你输出

2
3
11
111
a
b

当然这只是一个快速简单的例子。更好的实现取决于您。

下面是我自己终于想出来的。这肯定是一个快速而肮脏的解决方案,它会减慢已经很慢的速度

(与 jEdit [插件]->[文本工具]->[排序行] 或 bash 命令行 'sort -g' 相比)

对巨大的文本行缓冲区进行排序的过程,但它至少可以使用并按预期工作。为了完整起见,我的 Lua SciTE 启动脚本中目前存在的整个代码部分:

-- =============================================================================
-- Sort Selected Lines (available in MENU -> Tools):
-- -----------------------------------------------------------
-- Specify in .SciTEUser.properties:
--     command.name.2.*=# Sort Selected Lines    '
--     command.subsystem.2.*=3
--     command.mode.2.*=savebefore:no
--     command.2.*=SortSelectedLines
--     # command.shortcut.2.*=Ctrl+2 # Ctrl+2 is DEFAULT for command.2.*

function lines(str)
  local t = {}
  local i, lstr = 1, #str
  while i <= lstr do
    local x, y = string.find(str, "\r?\n", i)
    if x then t[#t + 1] = string.sub(str, i, x - 1)
    else break
    end
    i = y + 1
  end
  if i <= lstr then t[#t + 1] = string.sub(str, i) end
  return t
end

-- It was an annoying for me that using table.sort(buffer) in Lua  
-- didn't sort numbers with leading spaces in their numerical order. 
-- Using following comparison function helps to avoid that problem: 
function compare(a,b)
  return a:gsub(" ", "0") < b:gsub(" ", "0")
-- If 'compare' is not used ( table.sort(buf) )
-- Lua uses implicit for sorting (see Lua tutorial): 
--   return a < b
-- so changing the provided return statement to this above
-- would be enough to restore sorting to how it was before 
end

function SortSelectedLines()
  local sel = editor:GetSelText()
  if #sel == 0 then return end
  local eol = string.match(sel, "\n$")
  local buf = lines(sel)
  table.sort(buf, compare)
--table.foreach (buf, print) --used for debugging
  local out = table.concat(buf, "\n")
  if eol then out = out.."\n" end
  editor:ReplaceSel(out)
end

--  ---------
-- :Sort Selected Lines
-- -----------------------------------------------------------------------------