1 /* This Source Code Form is subject to the terms of the Mozilla Public
2 * License, v. 2.0. If a copy of the MPL was not distributed with this
3 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
6 * Natural Sort algorithm for Javascript - Version 0.8.1 - Released under MIT license
7 * Author: Jim Palmer (based on chunking idea from Dave Koelle)
9 * Includes pull request to move regexes out of main function for performance
13 * https://github.com/overset/javascript-natural-sort/
18 var re = /(^([+\-]?\d+(?:\.\d*)?(?:[eE][+\-]?\d+)?(?=\D|\s|$))|^0x[\da-fA-F]+$|\d+)/g;
19 var sre = /^\s+|\s+$/g; // trim pre-post whitespace
20 var snre = /\s+/g; // normalize all whitespace to single ' ' character
22 // eslint-disable-next-line
23 var dre = /(^([\w ]+,?[\w ]+)?[\w ]+,?[\w ]+\d+:\d+(:\d+)?[\w ]?|^\d{1,4}[\/\-]\d{1,4}[\/\-]\d{1,4}|^\w+, \w+ \d+, \d{4})/;
24 var hre = /^0x[0-9a-f]+$/i;
29 exports.naturalSortCaseSensitive = function naturalSortCaseSensitive(a, b) {
30 return naturalSort(a, b, false);
33 exports.naturalSortCaseInsensitive = function naturalSortCaseInsensitive(a, b) {
34 return naturalSort(a, b, true);
38 * Sort numbers, strings, IP Addresses, Dates, Filenames, version numbers etc.
39 * "the way humans do."
41 * This function should only be called via naturalSortCaseSensitive and
42 * naturalSortCaseInsensitive.
44 * e.g. [3, 2, 1, 10].sort(naturalSort)
47 * Passed in by Array.sort(a, b)
49 * Passed in by Array.sort(a, b)
50 * @param {Boolean} insensitive
51 * Should the search be case insensitive?
53 // eslint-disable-next-line complexity
54 function naturalSort(a, b, insensitive) {
55 // convert all to strings strip whitespace
56 const i = function(s) {
57 return ((insensitive && ("" + s).toLowerCase()) || "" + s).replace(sre, "");
63 .replace(re, "\0$1\0")
68 .replace(re, "\0$1\0")
72 // numeric, hex or date detection
73 const xD = parseInt(x.match(hre), 16) || (xN.length !== 1 && Date.parse(x));
75 parseInt(y.match(hre), 16) || (xD && y.match(dre) && Date.parse(y)) || null;
76 const normChunk = function(s, l) {
77 // normalize spaces; find floats not starting with '0', string or 0 if
78 // not defined (Clint Priest)
80 ((!s.match(ore) || l == 1) && parseFloat(s)) ||
81 s.replace(snre, " ").replace(sre, "") ||
88 // first try and sort Hex codes or Dates
97 // natural sorting through split numeric strings and default strings
98 // eslint-disable-next-line
99 for (let cLoc = 0, xNl = xN.length, yNl = yN.length, numS = Math.max(xNl, yNl); cLoc < numS; cLoc++) {
100 oFxNcL = normChunk(xN[cLoc] || "", xNl);
101 oFyNcL = normChunk(yN[cLoc] || "", yNl);
103 // handle numeric vs string comparison - number < string - (Kyle Adams)
104 if (isNaN(oFxNcL) !== isNaN(oFyNcL)) {
105 return isNaN(oFxNcL) ? 1 : -1;
107 // if unicode use locale comparison
108 // eslint-disable-next-line
109 if (/[^\x00-\x80]/.test(oFxNcL + oFyNcL) && oFxNcL.localeCompare) {
110 const comp = oFxNcL.localeCompare(oFyNcL);
111 return comp / Math.abs(comp);
113 if (oFxNcL < oFyNcL) {
115 } else if (oFxNcL > oFyNcL) {