Posted by
| Nick Gammon
Australia (23,122 posts) Bio
Forum Administrator |
Message
| Here's a nifty idea I found on this web page:
http://www.davekoelle.com/alphanum.html
The idea is to solve the problem of sorting lists into a way that humans are going to read. For example, filenames, or lists of parts.
Using standard sorting, a list of file names might be sorted like this:
Z9A.doc
z1.doc
z10.doc
z100.doc
z101.doc
z102.doc
z11.doc
z12.doc
z13.doc
z14.doc
z15.doc
z16.doc
z17.doc
z18.doc
z19.doc
z2.doc
z20.doc
z3.doc
z4.doc
z5.doc
z6.doc
z7.doc
z8.doc
z9.doc
Whilst this is in "string" sort order, it doesn't make a heap of sense, because for one thing the capitalized file name is a long way from the lower-case file name, and for another, files z1.doc and z2.doc are not next to each other.
Using the algorithm below (saved as a Lua module) you get more natural results:
z1.doc
z2.doc
z3.doc
z4.doc
z5.doc
z6.doc
z7.doc
z8.doc
z9.doc
Z9A.doc
z10.doc
z11.doc
z12.doc
z13.doc
z14.doc
z15.doc
z16.doc
z17.doc
z18.doc
z19.doc
z20.doc
z100.doc
z101.doc
z102.doc
The sort function works by breaking each string into "chunks" of either strings or numbers and then comparing each chunk correctly (numeric compare for numbers, string compare for strings).
To use it, save between the lines as alphanum.lua in your MUSHclient Lua directory, and then use it as per the example below.
-- alphanum.lua
--
-- Adapted somewhat from: http://www.davekoelle.com/files/alphanum.lua
-- Also see: http://www.davekoelle.com/alphanum.html
--
-- Implements a sort function that does a more "human readable" sort order.
-- It breaks the sort strings into "chunks" and then compares each one naturally,
-- depending on whether it is a string or a number (eg. z9.doc compares less than z20.doc)
-- It also does a case-insensitive compare (so "nick" and "Nick" come out together).
--[[
Example:
require "alphanum"
t={
"z18.doc","z19.doc","z2.doc","z16.doc","z17.doc",
"z1.doc","z101.doc","z102.doc","z11.doc","z12.doc",
"z13.doc","z14.doc","z15.doc","z20.doc","z3.doc",
"z4.doc","z5.doc","z6.doc","z10.doc","z100.doc",
"z7.doc","z8.doc","z9.doc", "Z9A.doc",
}
table.sort(t, alphanum)
for i=1, #t do
print(t[i])
end
--]]
local function chunkString(str)
local c = {}
for a, b in str:gmatch("(%d*)(%D*)") do
if a ~= "" then c[#c+1] = tonumber(a) end
if b ~= "" then c[#c+1] = b end
end
return c
end
function alphanum (a, b)
local achunks = chunkString(a)
local bchunks = chunkString(b)
for i = 1, math.min (#achunks, #bchunks) do
local as, bs = achunks [i], bchunks [i]
-- if one is a string, make them both strings
if type (as) == "string" or type (bs) == "string" then
as = (tostring (as)):upper ()
bs = (tostring (bs)):upper ()
end -- at least one is a string
-- if they are equal, move onto the next chunk
if as ~= bs then
return as < bs
end
end
-- still equal? the one with fewer chunks compares less
return #achunks < #bchunks
end
return alphanum
|
- Nick Gammon
www.gammon.com.au, www.mushclient.com | Top |
|