RosettaCodeData/Task/Natural-sorting/Jq/natural-sorting-1.jq

59 lines
2.3 KiB
Text
Raw Permalink Normal View History

2016-12-05 23:44:36 +01:00
def splitup:
def tidy: if .[0] == "" then .[1:] else . end | if .[length-1] == "" then .[0:length-1] else . end ;
# a and b are assumed to be arrays:
def alternate(a;b):
reduce range(0; [a,b] | map(length) | max) as $i ([]; . + [a[$i], b[$i]]);
([splits("[0-9]+")] | tidy) as $a
| ([splits("[^0-9]+")] | tidy | map(tonumber)) as $n
| (test("^[0-9]")) as $nfirst
| if $nfirst then alternate($n; $a) else alternate($a; $n) end ;
# The following implementation of tr is more general than needed here, but the generality
# makes for adaptability.
# x and y should both be strings defining a character-by-character translation, like Unix/Linux "tr".
# if y is shorter than x, then y will in effect be padded with y's last character.
# The input may be a string or an exploded string (i.e. an array);
# the output will have the same type as the input.
def tr(x;y):
type as $type
| (x | explode) as $xe
| (y | explode) as $ye
| $ye[-1] as $last
| if $type == "string" then explode else . end
| map( . as $n | ($xe|index($n)) as $i | if $i then $ye[$i]//$last else . end)
| if $type == "string" then implode else . end;
# NOTE: the order in which the filters are applied is consequential!
def natural_sort:
def naturally:
gsub("\\p{M}"; "") # combining characters (accents, umlauts, enclosures, etc)
| tr("ÀÁÂÃÄÅàáâãäåÇçÈÉÊËèéêëÌÍÎÏìíîïÒÓÔÕÖØòóôõöøÑñÙÚÛÜùúûüÝÿý";
"AAAAAAaaaaaaCcEEEEeeeeIIIIiiiiOOOOOOooooooNnUUUUuuuuYyy")
# Ligatures:
| gsub("Æ"; "AE")
| gsub("æ"; "ae")
| gsub("\u0132"; "IJ") # IJ
| gsub("\u0133"; "ij") # ij
| gsub("\u0152"; "Oe") # Œ
| gsub("\u0153"; "oe") # œ
| gsub("ffl"; "ffl")
| gsub("ffi"; "ffi")
| gsub("fi" ; "fi")
| gsub("ff" ; "ff")
| gsub("fl" ; "fl")
# Illustrative replacements:
| gsub("ß" ; "ss") # German scharfes S
| gsub("ſ|ʒ"; "s") # LATIN SMALL LETTER LONG S and LATIN SMALL LETTER EZH
| ascii_downcase
| gsub("\\p{Cc}+";" ") # control characters
| gsub("^(the|a|an) "; "") # leading the/a/an (as words)
| gsub("\\s+"; " ") # whitespace
| sub("^ *";"") # leading whitespace
| sub(" *$";"") # trailing whitespace
| splitup # embedded integers
;
sort_by(naturally);