JavaScript 中的数字、英文、汉字拼音排序

2022-07-15 · 529 chars · 3 min read

这两天看自己博客,发现标签页的排序有点奇怪,汉字没有按照拼音顺序排,我自己都找不到。当时写代码的时候直接用了 sort,只大概看了一眼,字母排序是对的,字母也在汉字前面,就没太在意细节,今天找标签的时候才发现问题。

这是之前的代码:

tags.sort((a, b) => {
  return a.group < b.group ? -1 : 1
})

代码简单粗暴。但是按照我预期的逻辑,应该是按数字、英文字母、汉字拼音的顺序排。这里就有一个问题,汉字字符串、数字、英文这些怎么比大小?MDN 上是这么写的:

  • First, objects are converted to primitives using Symbol.ToPrimitive with the hint parameter be 'number'.
  • If both values are strings, they are compared as strings, based on the values of the Unicode code points they contain.
  • Otherwise JavaScript attempts to convert non-numeric types to numeric values:
    • Boolean values true and false are converted to 1 and 0 respectively.
    • null is converted to 0.
    • undefined is converted to NaN.
    • Strings are converted based on the values they contain, and are converted as NaN if they do not contain numeric values.
  • If either value is NaN, the operator returns false.
  • Otherwise the values are compared as numeric values.

简单讲就是:

  • 都是字符串,按照 Unicode
  • 否则,字符串尝试转为数字再比较(js 弱类型),转不了就是 NaN
  • NaN 大于数字

所以说...对比的时候要把汉字单独拎出来,汉字 Unicode 的顺序和拼音并不一致,直接上新代码:

// 注意 tags 里面全部为 string
const tags = ['标', 'a', 'g', '2', 'x', '1', '张', '前']

const sortedTags = tags.sort((a, b) => {
  const regexp = /[a-zA-Z0-9]/

  if (regexp.test(a) || regexp.test(b)) {
    // a b 中有至少一个数字、字母的,还是老办法
    // 我这里忽略了大小写,你按照你的需求来
    return a.toLowerCase() < b.toLowerCase() ? -1 : 1
  } else {
    // 中文的,用 localeCompare
    return a.localeCompare(b, 'zh')
  }
})

console.log(sortedTags)

// output
// (8) ['1', '2', 'a', 'g', 'x', '标', '前', '张']

不熟悉 localeCompare 的看这个文档

赞赏

微信