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

ptr*_*trn 140 javascript sorting natural-sort

我正在寻找一种最简单的方法来排序由数字和文本组成的数组,以及这些数组的组合.

例如

'123asd'
'19asd'
'12345asd'
'asd123'
'asd12'
Run Code Online (Sandbox Code Playgroud)

变成

'19asd'
'123asd'
'12345asd'
'asd12'
'asd123'
Run Code Online (Sandbox Code Playgroud)

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

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

我是用JavaScript编写的.

编辑:正如adormitu指出的那样,我正在寻找的是一种自然分类的功能

fro*_*975 255

现在,在使用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));
Run Code Online (Sandbox Code Playgroud)

  • upvote为现代单行+1! (21认同)
  • 如果要对对象数组进行排序,还可以使用Collat​​or:https://codepen.io/TimPietrusky/pen/rKzoGN (8认同)
  • 为了澄清上述评论:“如果未提供或未定义区域设置参数,则使用运行时的默认区域设置。” (3认同)
  • 很棒,不错的方法 (2认同)
  • @Jayden 我们传递 undefined 以避免必须指定区域设置,它将使用浏览器的默认区域设置。 (2认同)

mhi*_*tza 45

所以你需要一个自然的类型

如果是这样,Brian Huisman根据David koelle的作品制作的剧本可能就是你所需要的.

似乎Brian Huisman的解决方案现在直接托管在David Koelle的博客上:

  • @mhitza这段代码似乎做得很好https://github.com/litejs/natural-compare-lite看到快速测试http://jsbin.com/bevututodavi/1/edit?js,console (2认同)

D0r*_*nd0 30

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

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

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


ken*_*bec 23

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

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;
}
Run Code Online (Sandbox Code Playgroud)

但是为了快速排序数组,在​​排序之前对数组进行装配,因此您只需要执行小写转换和正则表达式,而不是在排序的每个步骤中进行.

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];
    }
}
Run Code Online (Sandbox Code Playgroud)


Ste*_*uan 6

想象一个数字零填充函数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
Run Code Online (Sandbox Code Playgroud)

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

[
  "00000019asd",
  "00000123asd",
  "00012345asd",
  "asd00000012",
  "asd00000123"
]
Run Code Online (Sandbox Code Playgroud)

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

[
  "19asd",
  "123asd",
  "12345asd",
  "asd12",
  "asd123"
]
Run Code Online (Sandbox Code Playgroud)


Jul*_*ien 5

截至 2019 年,处理此问题的功能最齐全的库似乎是natural-orderby

import { orderBy } from 'natural-orderby'

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

const ordered = orderBy(unordered)

// [ '19asd',
//   '123asd',
//   '12345asd',
//   'asd12',
//   'asd123' ]
Run Code Online (Sandbox Code Playgroud)

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

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