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

IT技术 javascript sorting natural-sort
2021-01-20 02:11:12

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

例如

'123asd'
'19asd'
'12345asd'
'asd123'
'asd12'

变成

'19asd'
'123asd'
'12345asd'
'asd12'
'asd123'

这将与我在此处提出的另一个问题的解决方案结合使用

排序功能本身有效,我需要的是一个可以说“19asd”小于“123asd”的功能。

我正在用 JavaScript 写这个。

编辑:正如adormitu指出的那样,我正在寻找的是自然排序的功能

6个回答

这现在可以在使用 localeCompare 的现代浏览器中实现。通过传递numeric: true选项,它将巧妙地识别数字。您可以使用sensitivity: 'base'. 在 Chrome、Firefox 和 IE11 中测试。

这是一个例子。它返回1,这意味着 10 在 2 之后:

'10'.localeCompare('2', undefined, {numeric: true, sensitivity: 'base'})

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

在比较大量字符串时,例如对大型数组进行排序时,最好创建一个 Intl.Collat​​or 对象并使用其 compare 属性提供的函数。文档链接

var collator = new Intl.Collator(undefined, {numeric: true, sensitivity: 'base'});
var myArray = ['1_Document', '11_Document', '2_Document'];
console.log(myArray.sort(collator.compare));

澄清上述评论:“如果未提供或未定义语言环境参数,则使用运行时的默认语言环境。”
2021-03-25 02:11:12
如果要对对象数组进行排序,也可以使用整理器:codepen.io/TimPietrusky/pen/rKzoGN
2021-03-30 02:11:12

所以你需要一个自然排序

如果是这样,那么也许这个由 Brian Huisman 基于 David koelle 的作品编写的脚本将是您所需要的。

看起来 Brian Huisman 的解决方案现在直接托管在 David Koelle 的博客上:

@mhitza 这段代码似乎做得很好github.com/litejs/natural-compare-lite查看快速测试jsbin.com/bevututodavi/1/edit?js,console
2021-03-10 02:11:12
@tchrist:“它不产生字母排序”是什么意思?
2021-03-11 02:11:12
正确,自然的排序是我正在寻找的。我去看看你发的链接,谢谢
2021-03-26 02:11:12
它工作正常,但不能正确处理负数。即:它会产生 ['-1'. “-2”、“0”、“1”、“2”]。
2021-03-27 02:11:12
这是非常不自然的一种。它不会产生字母排序。
2021-04-01 02:11:12

如果你有一个对象数组,你可以这样做:

myArrayObjects = myArrayObjects.sort(function(a, b) {
  return a.name.localeCompare(b.name, undefined, {
    numeric: true,
    sensitivity: 'base'
  });
});

要比较值,您可以使用比较方法 -

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;
}

但是为了加快对数组的排序,请在排序之前对数组进行绑定,这样您只需进行一次小写转换和正则表达式,而不是在排序的每一步中进行。

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];
    }
}
这在我的情况下是否有效,内部数组决定外部数组的顺序?
2021-03-13 02:11:12
抱歉错误更正,谢谢。如果你想要 a[1] 和 b[1] 来控制排序,使用 a= String(a[1]).toLowerCase(); b= String(b[1]).toLowerCase();
2021-03-15 02:11:12
我只是有一个我想要排序的数据列表,认为在 Chrome Dev Tools 控制台中应该很容易做到 - 感谢您的功能!
2021-03-24 02:11:12
什么String.prototype.tlc()这是你自己的代码还是你从某个地方得到的?如果是后者,请链接到该页面。
2021-04-05 02:11:12

想象一个数字零填充函数n => n.padStart(8, "0"),它接受任何数字并填充它,即

  • “19”->“00000019”
  • “123”->“00000123”

此函数可用于帮助对"19"字符串进行排序,使其出现在"123"字符串之前

让我们添加一个正则表达式来/\d+/g创建自然扩展函数str => str.replace(/\d+/g, n => n.padStart(8, "0")),它只找到字符串中的数字部分并填充它们,即

  • “19asd”->“00000019asd”
  • “123asd”->“00000123asd”

现在,我们可以使用这个自然展开函数来帮助实现自然顺序排序:

const list = [
    "123asd",
    "19asd",
    "12345asd",
    "asd123",
    "asd12"
];

const ne = str => str.replace(/\d+/g, n => n.padStart(8, "0"));
const nc = (a,b) => ne(a).localeCompare(ne(b));

console.log(list.map(ne).sort()); // intermediate values
console.log(list.sort(nc); // result

演示的中间结果list.map(ne).sort()显示了ne自然扩展函数的作用。它仅在字符串的数字部分实现数字零填充,并保持字母组件不变。

[
  "00000019asd",
  "00000123asd",
  "00012345asd",
  "asd00000012",
  "asd00000123"
]

解决方案的最终版本实现了一个自然顺序比较器nc(a,b) => ne(a).localeCompare(ne(b))并使用它来list.sort(nc)正确排序:

[
  "19asd",
  "123asd",
  "12345asd",
  "asd12",
  "asd123"
]