字符串之间的比较之 localeCompare

很多人比较字符串基本上都是用 > 或者 < 比较

还有些人使用 localeCompare,但是你真的会用这个 原型方法 吗?

这里举个例子来说明一下如何比较 字符串中的数字

// 当我们比较 '10' 和 '9' 的时候,返回值小于0
'10'.localeCompare('9') // -1

那么如果我们遇到这种情况,其实 localeCompare 这个方法还提供了很多参数来比较

// locale 参数
'10'.localeCompare('9', 'zh-u-kn-true') // 1
'a'.localeCompare('A', 'zh-u-kf-upper') // 1
'a'.localeCompare('A', 'zh-u-kf-lower') // -1

// locale u 后边可以添加多种参数,比如 zh-u-kf-lower-kn-true

// options 参数
'10'.localeCompare('9', 'zh', { numeric: true }) // 1
'a'.localeCompare('A', 'zh', { caseFirst: 'upper' }) //1
'a'.localeCompare('A', 'zh', { caseFirst: 'lower' }) // -1

kn指定数值排序是否应该被使用,像是这样 "1" < "2" < "10"。可能的值是 "true" 和 "false"

kf 指定是否优先对大写字母或小写字母排序。可能的值有 "upper""lower", 或 "false"

 切勿依赖于 -1 或 1 这样特定的返回值。不同浏览器之间(以及不同浏览器版本之间)返回的正负数的值各有不同,因为 W3C 规范中只要求返回值是正值和负值,而没有规定具体的值。一些浏览器可能返回 -2 或 2 或其他一些负的、正的值。

所以我们判断的时候必须是根据它们 大于 0,小于 0,或者等于 0 来判断

locales 参数必须是一个 BCP 47 语言标记的字符串,或者是一个包括多个语言标记的数组。如果 locales 参数未提供或者是 undefined,便会使用运行时默认的 locale。

一个 BCP 47 语言标记代表了一种语言或者区域(两者没有很大的区别)。在其最常见的格式中,它以这样的顺序囊括了这些内容:语言代码,脚本代码,和国家代码,全部由连字符分隔开。例如:

  • "hi":印地语 (primary language)。
  • "de-AT"在奥地利使用的德语 (primary language with country code)。
  • "zh-Hans-CN":在中国使用的简体中文 (primary language with script and country codes)。

"u" 代表 Unicode。它可以用于请求一个自定义区域特定行为的 CollatorNumberFormat,或者 DateTimeFormat 对象。例如:

  • "de-DE-u-co-phonebk":使用德语的电话簿排序变体,这会把元音变音扩展成字符对:ä → ae, ö → oe, ü → ue。
  • "th-TH-u-nu-thai":在数字格式中使用泰语的数值表示(๐, ๑, ๒, ๓, ๔, ๕, ๖, ๗, ๘, ๙)
  • "ja-JP-u-ca-japanese":在日期和时间格式化中使用日本的日历表示方式,所以 2013 会表示为平成 25

如果习惯用第三个参数 options 的话,可以将 locale 参数传 undefined 使用系统默认

options 是个对象,它支持下列的一些或全部属性

localeMatcher

地域匹配算法的使用。可能的值是 "lookup" 和 "best fit"; 默认的值是 "best fit"。更多相关的资料,请参考 Intl page.

usage指定比较的目标是排序或者是搜索。可能的值是 "sort" 和 "search";默认是 "sort".
sensitivity

指定排序程序的敏感度(Which differences in the strings should lead to non-zero result values.)可能的有:

  • "base": 只有不同的字母字符串比较是不相等的。举个例子: a ≠ ba = áa = A.
  • "accent": 只有不同的字母或读音比较是不相等的。举个例子: a ≠ ba ≠ áa = A.
  • "case": 只有不同的字母或大小写比较是不相等的。举个例子: a ≠ ba = áa ≠ A.
  • "variant": 不同的字母或读音及其它有区别的标志或大小写都是不相等的, 还有其它的差异可能也会考虑到。举个例子: a ≠ ba ≠ áa ≠ A.

    使用"sort"时,默认为"variant";"search"的使用依赖于语言环境
ignorePunctuation指定是否忽略标点。可能的值是 true and false; 默认为 false.
numeric是否指定使用数字排序,像这样 "1" < "2" < "10"。可能的值是 true 和 false;默认为 false。这个选项能被通过options 属性设置或通过 Unicode 扩展。假如两个都被设置了,则 options 优先。实现不用必须支持这个属性。
caseFirst指定大小写有限排序。可能的值有 "upper""lower" 或 "false" (use the locale's default); 默认为 "false". 这个选项能被通过 options 属性设置或通过 Unicode 扩展。假如两个都被设置了,则 options 优先。实现不用必须支持这个属性。

知道了这些之后,对于那些有很多拼凑来的数据我们就可以使用分割再排序

const a = 'abc12嘻嘻3AB哈哈C456abcABC789'
a.split(/([a-z]+|[0-9]+|[A-Z]+)/).filter(item => !!item)
// ['abc', '12', '嘻嘻', '3', 'AB', '哈哈', 'C', '456', 'abc', 'ABC', '789']
// 分割之后就可以根据不同的值进行排序
const arr = ["a-10-张三", "钱5", "A-9-赵5", '孙八', "a-10","a-9-李四", "A-10", "钱六", "A-10-张三", "a-10-李四", "A-10-李四"];

const toSeparate = (str) => {
  if (typeof str !== 'string') return
  const regex = /([a-z]+|[0-9]+|[A-Z]+)/
  return str.split(regex).filter(item => !!item)
}

// 个人觉得,不是同一个类型,比较就应该用默认,不用纠结根据类型获取不同比较
// 如果想分得更细,就自己加内容
const compare = new Intl.Collator('zh-u-kn-true-kf-lower').compare // 小写字母放在大写字母前面

arr.sort((one, other) => {
  const oneSeparate = toSeparate(one)
  const otherSeparate = toSeparate(other)

  while (oneSeparate.length && otherSeparate.length) {
    if (compare(oneSeparate[0], otherSeparate[0]) === 0) {
      oneSeparate.shift()
      otherSeparate.shift()
    } else {
      return compare(oneSeparate[0], otherSeparate[0])
    }
  }
  // 到这一步说明 某一个 已经没有值了
  if (oneSeparate[0] === otherSeparate[0]) return 0
  return oneSeparate[0] ? 1 : -1 // 表示有值的放在后边,没有值了的放在前面
});

console.log(arr);
// ['钱5', '钱六', '孙八', 'a-9-李四', 'a-10', 'a-10-李四', 'a-10-张三', 'A-9-赵5', 'A-10', 'A-10-李四', 'A-10-张三']

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值