Unicode 字符串排序规则(二):如何比较字符串
一、UCA 简介
Unicode Collation Algorithm (UCA) 是 Unicode 规定的如何比较两个字符串大小的算法,也是事实上的标准。我们先来看下它的几个特征。
1.1 Multi-Level Comparison
为了处理字符串比较的复杂性,UCA 采用了多级比较的方法。
当比较两个字符串时,先比较最重要的特征——字母。如果字母相同,再比较重音 (accent)。如果重音还相同,再比较大小写。依次类推,这些特征之间的顺序可以改变。

如上图所示,首先比较基本字符串,然后依次是 Accent、 Case、Punctuation等,最后比较是否完全相等。
一定要注意,Unicode 码点的顺序不是排序的依据。
The position of characters in the Unicode code charts does not specify their sort order.
为何要采样多级比较
考虑一个例子,我们有a < ä && e < ë && a < e && ä < ë,如果我们仅仅采用单级比较的话,显然有a < ä < e < ë。
比较字符串ae和äa。我们想要得到的结果肯定是äa < ae。如果按照单级比较的话,由于a < ä,我们会得到ae < äa。
使用多级比较,可以优先处理主要矛盾。
1.2 Canonical Equivalence
在 Unicode 中,可能出现两个不同码点序列表示的是同一个字符串,即这两个序列具有 Unicode等价性。这些具有 Unicode 等价性的字符串在排序时,应该被认为是同样的。下表是一些 Unicode 等价性的例子。

1.3 Contextual Sensitivity
在某些语言中,字符串的比较不仅仅是单个字符序列的比较,和字符出现的上下文有关。UCA 必须处理好这些事情,如下所示:

1.4 Customization
在实际使用中,UCA 应该可以处理一些用户自定义的规则,包括但不限于:
- Language。
排序结果应该符号目标语言使用者的预期。 - Case Ordering
有时大写在前,有时小写在前。 - Script Order
用户可能希望一种文字出现在另一种文字之前。
b < ב < β < б [Latin < Hebrew < Greek < Cyrillic] versus
β < b < б < ב [Greek < Latin < Cyrillic < Hebrew] - Numbers
用户可能希望把字符串按照数字排序,如A2 < A10。
二、UCA 排序算法处理过程
2.1 Normalize
使用 Unicode 规范化算法,把字符串以标准等价方式来分解 (Normalization Form Canonical Decomposition, NFD)。
2.2 Produce Array
对字符串中的每一个字符进行多级量化,转化为数组,便于之后的比较。

如上所示,每一个字符对应一个 collation element;每一个元素中用.分隔不同等级的权重的值。比如c的第一权重是0706,第二权重是0020,第三权重是0002。
2.3 Form Sort Key
把数组中所有非零权重的值按照等级连接起来,组成一个 sort key。


如果指定了只比较等级 1、2,那么等级 3 就不会在 sort key 中出现。
2.4 Compare
使用一种方法对字符串的 sort key 进行排序。下面是一个排序结果的例子。

最后的排序结果是"cab" <<< "Cab" << "cáb" < "dab$"。
- 对于字符串 1 和 2,第一个区别是 0002 VS 0008 (Level 3).
- 对于字符串 2 和 3,第一个区别是 0020 VS 0021 (Level 2).
- 对于字符串 3 和 4,第一个区别是 0706 VS 0712 (Level 1).
三、其他
- 生成Collation Element 时,具体的值可以被修改
CLDR 指定了如何根据语言和地区进行处理,还包括其他内容。 字符串有时需要预处理
在某些具体的情形下,需要进行预处理,下面是一些例子。- McBeth -> MacBeth
- St. -> Saint 或者 St. -> Street
- 去掉冠词
- 加入额外信息。对于汉字来说,有多音字。
UCA 只是规定了一个算法。具体的实现可以不同,只要保证和 UCA 结果相同。
四、参考
Unicode 字符串排序规则(二):如何比较字符串的更多相关文章
- Unicode 字符串排序规则(一):如何确定单个字符的顺序
一.一个具体的例子引发的问题 当今是国际化的时代,多种语言可能同时显示在屏幕上.比如一个人可能喜欢听华语歌.英文歌.韩文歌和日语歌,又比如他的联系人中有中国人.英国人.日本人.韩国人以及有英文名字的中 ...
- php中的字符串常用函数(二) substr() 截取字符串
//substr($str, startIndex, length) //截取方向都是从左向右的. //length不写默认截取到最后一个. //length为正是个数(包括开头的个数),为负是索引( ...
- OpenJudge计算概论-字符串排序
/*====================================================================== 字符串排序 总时间限制: 1000ms 内存限制: 6 ...
- Openjudge-计算概论(A)-字符串排序
描述 参考整数排序方法,设计一种为字符串排序的算法,将字符串从小到大输出 输入 第一行为测试数据组数t, 后面跟着t组数据.每组数据第一行是n,表示这组数据有n行字符串,接下来是要排序的n行字符串.每 ...
- 字符串之————图文讲解字符串排序(LSD、MSD)
本篇文章围绕字符串排序的核心思想,通过图示例子和代码分析的方式讲解了两个经典的字符串排序方法,内容很详细,完整代码放在文章的最后. 一.键索引计数法 在一般排序中,都要用里面的元素不断比较,而字符串这 ...
- 数据库排序规则的冲突(理解collate Chinese_PRC_CI_AS)
之前碰到了数据库排序规则冲突问题,即百度或者 Google 的老话题: “ 无法解决 equal to 操作中‘ sql_latin1_general_cp1_ci_as ’和‘ chinese_pr ...
- MS SQL 排序规则总结
排序规则术语 什么是排序规则呢? 排序规则是根据特定语言和区域设置标准指定对字符串数据进行排序和比较的规则.SQL Server 支持在单个数据库中存储具有不同排序规则的对象.MSDN解 ...
- sql server 排序规则
/* 排序规则根据特定语言和区域设置的标准指定对 字符串 数据 进行排序和比较的规则. 以 ORDER BY 子句为例:如果按升序排列,说英语的人认为字符串 Chiapas 应排在 Col ...
- sqlserver之排序规则和ETL不支持sqlserverdatetime2的问题
sqlserver的排序规则大概分为Windows 排序规则和 SQL Server 排序规则.数据在安装的时候,默认不设置会默认为SQL_Latin1_General_CP1_CI_AI.数据库在创 ...
随机推荐
- 本学期c#学习总结
本学期c#学习总结 时间转瞬即逝,大一上半学期的学习生涯已经结束.虽然以前我没什么关于学习计算机的基础,但是经过了这几个月的学习我也还是有点收获的. 我发现c#语言的关键词有很多语言特性和固定的用法, ...
- 史上最坑 idea 更改代码不生效
原来, 如果本地多次调整过系统时间,那么gradle 的缓存 会缓存 你的 上次编译时间再未来,那么你再怎么编译,都很难生效,即使删除了生成的字节码目录. 然后invalidate caches/re ...
- linux下redis4.0.2集群部署(利用Ruby脚本命令)
一.原生命令方式和Ruby脚本方式区别 利用Ruby脚本部署和用原生命令部署,节点准备的步骤都是一样的,节点启动后的握手,以及主从.槽分配,利用Ruby脚本一步就能完成,利用原生命令需要一步一步地执行 ...
- 使用JS读取本地文本文件(兼容各种浏览器)
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8&quo ...
- redis5 集群迁移方案
Redis5 集群迁移方案 一.KEY优化 1.按原来要求进行优化与大KEY分拆. 二.现Redis 集群缩容(对业务无影响) 主节点按要求合并至3个主节点. 业务配置为3主4从 删除没有槽的主节点与 ...
- Cocos2dx Android工程的启动过程
1.安卓工程下的设置启动activity为src下面的AppActivity,启动调用的onCreate并没有做过多的事情,只是调用了父类Cocos2dxActivity的onCreate.AppAc ...
- Idea+maven+testNG+Selenium+ReportNG自动化框架搭建
1.Idea创建一个空的Maven项目 创建后默认项目目录如图所示 2.配置pom.xml文件 <?xml version="1.0" encoding="UTF- ...
- 原子性 CAS算法
一. i++ 的原子性问题 1.问题的引入: i++ 的实际操作分为三个步骤:读--改--写 实现线程,代码如下: public class AtomicDemo implements Runnabl ...
- 用TSQL从sqlserve 发布订阅链中删除一张或几张表
一个简单的存储过程,用来实现从一个SQLSERVE 发布订阅链中删除一张或几张表. /* 1.停日志读取代理 2.exec usp_从复制订阅中删除表 'dbtestPub','test1' 3.开日 ...
- centos7切换图像界面和dos界面
在图形界面使用 ctrl+alt+F2切换到dos界面 dos界面 ctrl+alt+F2切换回图形界面 在命令上 输入 init 3 命令 切换到dos界面 输入 init 5命令 切换到图形界面 ...