文件名排序

2,277 阅读1分钟

对文件名进行排序是一个很经典的问题。

最直接的方法是,直接进行字符串比较:

files.sort((a, b) => a.name > b.name ? 1 : -1)

当然,这样的比较方式会存在的问题是,如果两个文件的文件名为11.jpg2.jpg,我们将获得的排序结果是['11.jpg', '2.jpg'],这与用户的直观理解是相悖的。

改进的方式是,先判断两个文件的文件名(去除文件扩展名)是否均为数字,如果是则先作为数字比对,否则作为字符串比较。

当然这还是不够的。用户可能对文件添加前后缀,例如item_a_23_preview.jpg2010-11-07-product-11.jpg

在Mac(Mojave)下文件名排序的结果如下:

在Mac(Mojave)下文件名排序的结果

这样的情况下,我们需要将文件名分割为字符串/数字的多段组合,再逐段比较,直到分出顺序。

我们通过一个正则就能完成这个分段的任务:

const regexp = /[^\d]+|\d+/g;

代码

const fileNames = ['a11c.jpg', 'a2c.jpg'];

const regexp = /[^\d]+|\d+/g;
const result = fileNames.map(name => ({ name, weights: name.match(regexp) })).sort((a, b) => {
  let pos = 0;
  const weightsA = a.weights;
  const weightsB = b.weights;
  let weightA = weightsA[pos];
  let weightB = weightsB[pos];
  while (weightA && weightB) {
    const v = weightA - weightB;
    if (!isNaN(v) && v !== 0) return v;
    if (weightA !== weightB) return weightA > weightB ? 1 : -1;
    pos += 1;
    weightA = weightsA[pos];
    weightB = weightsB[pos];
  }
  return weightA ? 1 : -1;
});

console.log(result.map(x => x.name));