无谓网刷信誉方法:js中的localeCompare到底是如何比较的?

    js中有一个sort方法,可以用来对数组排序,它有一个比较函数,用来比较两个元素的大小,我们先来看一个最基本的:

['2','10','3'].sort((a,b)=>{ return a-b;});

    上面我们写了一个最简单的sort,它的返回结果是['2','3','10']。

    上面的排序规则是先将字符串转成数字,然后按照数字大小排序的,因为字符串在遇到减号的时候,先转成Number,再进行计算。

    除了上面这种排序,还有一种排序规则:

['2','10','3'].sort((a,b)=>{ return a>b?1:-1;});

    上面排序的结果是["10", "2", "3"],为啥在这里’10‘是最小的?

    因为这里是按照ASCII码的大小进行排序的,‘10’第一个字符的ASCII码是49,'2'的ASCII码是50,因此'10'是要比'2'小。我们在浏览器中输入'10'<'2',可以发现是true。

    除了上面两种常见的比较,还有一种比较方法localeCompare。

    localeCompare是个啥东东

    localeCompare是一种基于国际化字体的地区字符比较,例如中国用中文,美国用英文,法国用法文,德国用德文。。将这些国家的文字按照国家/地区等进行编号,然后每个编号都对应了该国/地区的文字。

    简单一点理解,就是你可以想象有一个map,key是这些国家/地区的编号,例如汉字,zh-CN;英文,en-US等,它们的value就对应了改国/地区的文字。   

    我们之前讲过一篇文章:js中的UTF-8编码与解码,里面有一个Unicode字符表,它是将全世界所有的语言文字统一进行编码,它和这里讲的国际化字符表不一样。

    Unicode字符表的目的是将所有的文字/符号进行编码,这样任意一个符号都可以通过一个编号进行表示,里面除了有全世界所有的文字,还有表情符号等;而国际化字符表的目的是为了区分不同国家/地址的文字,例如你的页面现在是中文的,想翻译成英文版的,那么就切换到英文的文字,然后用英文对他进行翻译。

    也就是Unicode字符表中无法区分字符是哪个国家的,而国际化字符表可以区分不同语言。

    注意这两个表除了用途不一样,对字符的编码顺序也是不同的,这点很重要,我之前就是没有理解这一点,因此有些问题无法理解。

    数字/英文的顺序

    ASCII码我们平时听的比较多,它会对数字/符号/英文字符进行编号,例如'a'是97,'A'是65等,我们看看常见的数字/英文的ASCII排序顺序:

'0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ'.split('').sort((a,b)=>a>b?1:-1).join('');//结果:0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz

    我们可以看到,用>号比较的就是按照ASCII码的排序顺序。那么我们来看localeCompare的结果:

'0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ'.split('').sort((a,b)=>a.localeCompare(b)).join('');//结果:0123456789aAbBcCdDeEfFgGhHiIjJkKlLmMnNoOpPqQrRsStTuUvVwWxXyYzZ

    我们可以看到最显著的差别就是在国际化字符表中,英文的顺序是小写/大写,小写/大写,。。。而上面的ASCII码是大写,大写,。。小写,小写。。。

    这会导致什么问题呢?我之前看到有这样一个问题:

'B'.localeCompare('a');//结果1

    上面的意思是说,在字符表中,B在a的后面,他就怎么都想不通,为啥B在a的后面?在ASCII表中,B明显在a的前面啊,怎么跑到后面去了?

    因为他没有搞清楚ASCII表和国际字符表是不同的,如果你想验证在ASCII码的关系,正确的简单验证方法如下:

'B'<'a'//结果:true

    上面验证的才是ASCII表中的顺序。

    中文的顺序   

    localeCompare被提及最多的就是可以将中文按照拼音的顺序进排序,那我们现在就来验证一下,它对中文的排序到底如何。

    这里我们要借助我们小时候背的字母歌来进行测试,我们先来个普通的测试:

'啊波次的俄佛歌,何以饥渴了么呢,我泼漆,日斯特,无谓网,洗鸭子'.split('').sort((a,b)=>a.localeCompare(b)).join('');//结果:,,,,,么了以何佛俄呢啊子我斯无日次歌波泼洗渴漆特的网谓饥鸭

    我们看到,在默认的情况下,localeCompare并没有按照拼音的顺序排序,那么这是什么顺序?猜测可能是unicode码顺序,我们测试下:

'啊波次的俄佛歌,何以饥渴了么呢,我泼漆,日斯特,无谓网,洗鸭子'.split('').sort((a,b)=>a.charCodeAt(0)-b.charCodeAt(0)).join('');//结果:么了以何佛俄呢啊子我斯无日次歌波泼洗渴漆特的网谓饥鸭,,,,,

    我们可以看到,默认情况下,localeCompare是按照unicode字符标的顺序来的。同时我们还可以发现,在unicode字符标中,符号在文字后面;在国际字符表中,符号在文字前面。

    localeCompare还有一个参数,表示参照那个国家/地区的字符标表,我们设置为中文('zh-CN'),我们再测试一次:

'啊波次的俄佛歌,何以饥渴了么呢,我泼漆,日斯特,无谓网,洗鸭子'.split('').sort((a,b)=>a.localeCompare(b,'zh-CN')).join('');//结果,,,,,啊波次的俄佛歌何饥渴了么呢泼漆日斯特网谓我无洗鸭以子

    我们看到大部分按照拼音了,但是好像有几个汉字乱了,那是因为有几个字母开头的没有汉字,是模拟的汉字,如:‘以’模拟i,‘我’模拟o,‘无'模拟u,‘谓'模拟v,认真比对后发现,确实是按照拼音来的。

    我们再测试一个:

'一二三四五六七八九十'.split('').sort((a,b)=>a.localeCompare(b,'zh-CN')).join('');//结果八二九六七三十四五一拼音如下:ba er jiu liu qi san shi si wu yi

    我们可以发现,localeCompare确实是按照拼音顺序来的。

    中文多音字

    多音字是比较麻烦的,localeCompare无法正确比较多音字,例如凹,可以读作ao或者wa,wa是少数读音,ao是多数读音,比较的时候只能比较出作为ao的读音,无法比较出wa的读音,例如:

'啊'.localeCompare('凹','zh-CN');//-1,啊在凹前面'吧'.localeCompare('凹','zh-CN');//1//吧在凹后面

     上面的测试说明凹的读音介于a,b之间,读作ao。

    指定汉字拼音首字母

    利用localCompare的特性,我们可以得到指定拼音首字母的汉字,代码如下:

function sort(array, key) { if(!key.toLocaleLowerCase().match(/[a-z]/ || !Array.isArray(array) || array.length === 0)) { throw Error('传的参数有问题') } function compare(a, b) { return a.localeCompare(b, 'zh-CN') } const letters = 'abcdefghjklmnopqrstwxyz'.split(''), zh = '阿八嚓哒妸发旮哈讥咔垃痳拏噢妑七呥扨它穵夕丫帀'.split(''), index = key && letters.indexOf(key.toLocaleLowerCase()), result = [] array.forEach(value => { if(value[0].toLocaleLowerCase() === key.toLocaleLowerCase() || compare(zh[index],value[0]) <= 0 && (!zh[index + 1] || compare(value[0], zh[index+1]) < 0)) { result.push(value) } }) result.sort((a, b) => compare(a, b)) return result}sort(['啊','波','次','得'],'a');["啊"]

    上面指定拼音首字母为a,那么可以将其他的汉字过滤掉。

    它的原理就是找到以26个字母为拼音开头的第一个汉字。这里是'阿八嚓哒妸发旮哈讥咔垃痳拏噢妑七呥扨它穵夕丫帀'。

    然后判断它们的前后关系,例如以a开头的,用localeCompare比较,汉字在'阿'后面,'八'前面的,肯定就是a开头了。

    可能有人要问了,你咋知道这几个汉字代表它拼音首字母的第一个汉字呢?这个很简单,在‘新华词典’上找,我们可以找一个在线的:在线汉语词典,我们截个图看看:

    

    上面罗列了所有的可读拼音,我们只要看每个字母第一个可读的,例如我们随便找一个:

    例如r开头的第一个是ran(2声),我们得到了13个汉字,我们再用localeCompare计算出里面最小的那个即可得到r开头最小的汉字。其实我们基本可以发现,第一排第一个汉字就是最小的(可能按照比划来的)。

   但是同样注意,有多音词的:

    

    按道理来说夹在旮前面,但是因为夹是多音词,因此夹被放在了j开头的拼音里面(jia)。因此g开头第一个汉字是旮。

转载于:http://www.qiutianaimeili.com/html/page/2020/07/20207171bfbctvh896.html

相关推荐

相关文章