Javascript:字母数字字符串的自然排序

Javascript:字母数字字符串的自然排序,javascript,sorting,natural-sort,Javascript,Sorting,Natural Sort,我正在寻找对由数字和文本组成的数组以及它们的组合进行排序的最简单方法 例如 变成 '19asd' '123asd' '12345asd' 'asd12' 'asd123' 这将与解决方案结合使用 排序函数本身可以工作,我需要的是一个函数,可以说'19asd'比'123asd'小 我是用JavaScript写的 编辑:正如adormitu指出的,我正在寻找的是一个自然排序的函数所以你需要一个自然排序 如果是这样的话,那也许就是你所需要的 看起来Brian Huisman的解决方案现在直接托管在D

我正在寻找对由数字和文本组成的数组以及它们的组合进行排序的最简单方法

例如

变成

'19asd'
'123asd'
'12345asd'
'asd12'
'asd123'
这将与解决方案结合使用

排序函数本身可以工作,我需要的是一个函数,可以说'19asd'比'123asd'小

我是用JavaScript写的


编辑:正如adormitu指出的,我正在寻找的是一个自然排序的函数

所以你需要一个自然排序

如果是这样的话,那也许就是你所需要的

看起来Brian Huisman的解决方案现在直接托管在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;
}
功能自然排序器(as、bs){
变量a,b,a1,b1,i=0,n,L,
rx=/(\.\d+)(\d+(\.\d+)))([^\d.]+)(\.\d+)(\.$)/g;
if(as==bs)返回0;
a=as.toLowerCase().match(rx);
b=bs.toLowerCase().match(rx);
L=a.长度;
而(ib1-1:-1;
}
}
返回b[i]?-1:0;
}
但是为了加快数组的排序速度,请在排序之前对数组进行装配, 因此,您只需进行小写转换和正则表达式 一次,而不是在排序的每一步中

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];
    }
}
函数自然排序(ar,索引){
var L=ar.length,i,who,next,
isi=typeof索引=='number',
rx=/(\.\d+)(\d+(\.\d+))([^\d.]+)(\.(\d+)))/g;
功能传感器(aa、bb){
变量a=aa[0],b=bb[0],a1,b1,i=0,n,L=a.长度;
而(ib1-1:-1;
}
}
返回b[i]!=未定义?-1:0;
}

对于(i=0;i这在使用localeCompare的现代浏览器中是可能的。通过传递
numeric:true
选项,它将智能地识别数字。您可以使用
sensitivity:'base'
,在Chrome、Firefox和IE11中测试,不区分大小写

下面是一个示例。它返回
1
,表示10在2之后:

'10'.localeCompare('2',未定义,{numeric:true,sensitivity:'base'})

对于排序大量字符串时的性能,文章说:

在比较大量字符串时,例如在对大型数组排序时,最好创建一个Intl.Collator对象并使用其compare属性提供的函数

var collator=new Intl.collator(未定义,{numeric:true,敏感度:'base'});
var myArray=['1_文档'、'11_文档'、'2_文档'];

console.log(myArray.sort(collator.compare));
基于上面@Adrien Be的答案,并使用创建的代码,这里是一个对象数组的修改原型排序:

//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"];
  }
}
//用法:unsortedarayofobjects.alphaNumObjectSort(“名称”);
//测试用例:var unsortedarayofobjects=[{name:“a1”},{name:“a2”},{name:“a3”},{name:“a10”},{name:“a5”},{name:“a20”},{name:“a8”},{name:“8b7uaf5q11”};
//排序:[{name:“8b7uaf5q11”},{name:“a1”},{name:“a2”},{name:“a3”},{name:“a5”},{name:“a8”},{name:“a10”},{name:“a13”},{name:“a20”}]
//**分类到位**
Array.prototype.alphaNumObjectSort=函数(属性,不区分大小写){
for(var z=0,t;t=this[z];z++){
此[z].sortArray=new Array();
变量x=0,y=-1,n=0,i,j;
而(i=(j=t[attribute].charAt(x++).charCodeAt(0)){
变量m=(i==46 | |(i>=48&&i-bb)?1:-1;
}
}
}
返回a.sortArray.length-b.sortArray.length;
});
对于(var z=0;z
想象一个8位数的填充函数,它可以转换:

  • “123asd”->“00000 123asd”
  • “19asd”->“00000019asd”
我们可以使用填充字符串帮助我们将“19asd”排序为出现在“123asd”之前

使用正则表达式
/\d+/g
帮助查找所有需要填充的数字:

str.replace(/\d+/g,pad)
下面演示如何使用此技术进行排序:

var列表=[
‘123asd’,
‘19asd’,
“12345asd”,
“asd123”,
“asd12”
];
功能板(n){return(“00000000”+n).substr(-8);}
函数自然_展开(a){返回a.replace(/\d+/g,pad)};
函数自然比较(a,b){
返回自然扩展(a)。本地比较(自然扩展(b));
}
console.log(list.map(natural_expand.sort());//中间值

console.log(list.sort(natural_compare));//result
如果您有一个对象数组,您可以这样做:

myArrayObjects = myArrayObjects.sort(function(a, b) {
  return a.name.localeCompare(b.name, undefined, {
    numeric: true,
    sensitivity: 'base'
  });
});
var myArrayObjects=[{
“id”:1,
“名称”:“1个示例”
},
{
“id”:2,
“名称”:“100个示例”
},
{
“id”:3,
“名称”:“12个示例”
},
{
“id”:4,
“名称”:“5个示例”
},
]
myArrayObjects=myArrayObjects.sort(函数(a,b){
返回a.name.localeCompare(b.name,未定义{
数字:对,
敏感度:“基本”
});
});

console.log(myArrayObjects);
到2019年为止,处理这个问题的功能最全的库似乎是

它不仅接受字符串数组,还可以根据对象数组中某个键的值进行排序。它还可以自动识别和排序字符串:货币、日期、货币和一系列其他内容


令人惊讶的是,gzip时它也只有1.6kB。

正确,我要找的是自然排序。我会查看你发送的链接,谢谢。这是一种非常不自然的排序。它不会产生阿尔卑斯排序。@tchrist:你说“它不会产生字母排序”是什么意思它工作正常,但不能正确处理负数。例如:它会产生['-1'.-2',0',1',2'.@mhiza此代码似乎做得很好。请看一个快速测试,在我的情况下,这是否有效,内部数组决定外部数组的顺序?什么是
String.prototype.tlc()
?这是您自己的代码还是您得到的
myArrayObjects = myArrayObjects.sort(function(a, b) {
  return a.name.localeCompare(b.name, undefined, {
    numeric: true,
    sensitivity: 'base'
  });
});
const { orderBy } = require('natural-orderby')

const unordered = [
  '123asd',
  '19asd',
  '12345asd',
  'asd123',
  'asd12'
]

const ordered = orderBy(unordered)

// [ '19asd',
//   '123asd',
//   '12345asd',
//   'asd12',
//   'asd123' ]