Javascript:自然sorting的字母数字string
我正在寻找最简单的方法来sorting由数字和文本,以及这些组成的数组。
例如
'123asd' '19asd' '12345asd' 'asd123' 'asd12'
变成
'19asd' '123asd' '12345asd' 'asd12' 'asd123'
这将与我在这里提出的另一个问题的解决scheme结合使用。
sortingfunction本身起作用,我需要的是一个函数,可以说“19asd”小于“123asd”。
我正在用JavaScript写这个。
编辑:如adormitu指出,我正在寻找是一个自然sortingfunction
现在在使用localeCompare的现代浏览器中这是可能的。 通过传递numeric: true
选项,它会巧妙地识别数字。 您可以使用sensitivity: 'base'
区分sensitivity: 'base'
。 在Chrome,Firefox和IE11中testing。
这是一个例子。 它返回1
,意味着10在2之后:
'10'.localeCompare('2', undefined, {numeric: true, sensitivity: 'base'})
为了在sorting大量string时的性能,文章说:
比较大量string时,比如在sorting大数组时,最好创build一个Intl.Collator对象,并使用compare属性提供的函数。
var collator = new Intl.Collator(undefined, {numeric: true, sensitivity: 'base'}); var myArray = ['1_Document', '11_Document', '2_Document']; myArray.sort(collator.compare); // myArray is now ['1_Document', '2_Document', '11_Document']
所以你需要一个自然的sorting ?
如果是这样的话,那么Brian Huisman根据David koelle的作品写的脚本可能就是你所需要的。
Brian Huisman的解决scheme似乎直接托pipe在David Koelle的博客上:
- Brian Huisman的javascript解决scheme
- David koelle关于这个问题的文章
要比较值,可以使用比较方法 –
function naturalSorter(as, bs){ var a, b, a1, b1, i= 0, n, L, rx=/(\.\d+)|(\d+(\.\d+)?)|([^\d.]+)|(\.\D+)|(\.$)/g; if(as=== bs) return 0; a= as.toLowerCase().match(rx); b= bs.toLowerCase().match(rx); L= a.length; while(i<L){ if(!b[i]) return 1; a1= a[i], b1= b[i++]; if(a1!== b1){ n= a1-b1; if(!isNaN(n)) return n; return a1>b1? 1:-1; } } return b[i]? -1:0; }
但是为了快速sorting数组,在sorting之前调整数组,所以你只需要做一次小写转换和一次正则expression式,而不是每一步都进行sorting。
function naturalSort(ar, index){ var L= ar.length, i, who, next, isi= typeof index== 'number', rx= /(\.\d+)|(\d+(\.\d+)?)|([^\d.]+)|(\.(\D+|$))/g; function nSort(aa, bb){ var a= aa[0], b= bb[0], a1, b1, i= 0, n, L= a.length; while(i<L){ if(!b[i]) return 1; a1= a[i]; b1= b[i++]; if(a1!== b1){ n= a1-b1; if(!isNaN(n)) return n; return a1>b1? 1: -1; } } return b[i]!= undefined? -1: 0; } for(i= 0; i<L; i++){ who= ar[i]; next= isi? ar[i][index] || '': who; ar[i]= [String(next).toLowerCase().match(rx), who]; } ar.sort(nSort); for(i= 0; i<L; i++){ ar[i]= ar[i][1]; } }
以@Adrien为基础Be是上面的答案,并使用Brian Huisman & David koelle创build的代码, 下面是一个对象数组的修改原型sorting:
//Usage: unsortedArrayOfObjects.alphaNumObjectSort("name"); //Test Case: var unsortedArrayOfObjects = [{name: "a1"}, {name: "a2"}, {name: "a3"}, {name: "a10"}, {name: "a5"}, {name: "a13"}, {name: "a20"}, {name: "a8"}, {name: "8b7uaf5q11"}]; //Sorted: [{name: "8b7uaf5q11"}, {name: "a1"}, {name: "a2"}, {name: "a3"}, {name: "a5"}, {name: "a8"}, {name: "a10"}, {name: "a13"}, {name: "a20"}] // **Sorts in place** Array.prototype.alphaNumObjectSort = function(attribute, caseInsensitive) { for (var z = 0, t; t = this[z]; z++) { this[z].sortArray = new Array(); var x = 0, y = -1, n = 0, i, j; while (i = (j = t[attribute].charAt(x++)).charCodeAt(0)) { var m = (i == 46 || (i >=48 && i <= 57)); if (m !== n) { this[z].sortArray[++y] = ""; n = m; } this[z].sortArray[y] += j; } } this.sort(function(a, b) { for (var x = 0, aa, bb; (aa = a.sortArray[x]) && (bb = b.sortArray[x]); x++) { if (caseInsensitive) { aa = aa.toLowerCase(); bb = bb.toLowerCase(); } if (aa !== bb) { var c = Number(aa), d = Number(bb); if (c == aa && d == bb) { return c - d; } else { return (aa > bb) ? 1 : -1; } } } return a.sortArray.length - b.sortArray.length; }); for (var z = 0; z < this.length; z++) { // Here we're deleting the unused "sortArray" instead of joining the string parts delete this[z]["sortArray"]; } }
成像一个8位数的填充函数,可以将“123asd”和“19asd”分别转换为“00000123asd”和“00000019asd”。 使用这些版本的string将帮助我们sorting“19asd”在“123asd”之前出现。
我们可以使用正则expression式/\d+/g
来帮助find所有需要填充的数字:
str.replace(/\d+/g, pad)
以下演示使用这种技术进行sorting:
var list = [ '123asd', '19asd', '12345asd', 'asd123', 'asd12' ]; function pad(n) { return ("00000000" + n).substr(-8); } function natural_expand(a) { return a.replace(/\d+/g, pad) }; function natural_compare(a, b) { return natural_expand(a).localeCompare(natural_expand(b)); } console.log(list.map(natural_expand).sort()); // intermediate values console.log(list.sort(natural_compare)); // result