Fork me on GitHub

Go语言开发-字符串-比较字符串

3.2.比较字符串

如前所述,Go语言字符串支持常规的比较操作符(<、<=、==、!=、>、>=),参见表2.3。比较操作符在内存中是逐字节的比较字符串。比较操作可以直接使用,例如,比较两个字符串是否相等,也可以间接使用,例如,对已经排好序的[]string使用<操作符比较其含有的字符串。遗憾的是,执行比较操作时可能会出现3个问题,这3个问题困扰着每个使用Unicode编码字符串的编程语言,这些问题折磨每种编程语言使用 Unicode 字符串,Go语言和它们并没有什么不同。

第一个问题是,有些Unicode编码的字符由两个或者多个不同的字节序列来表示。例如,字符Å可以是Ångström符号中的字符,或只是字符A上面带个圆圈,这两者在视觉上往往是无法区分的。Ångström符号的Unicode码点是U+212B,但是上面带有圆圈的A字符可以使用一个Unicode码点U+00C5或两个Unicode码点U+0041 (A) 和U+030A(结合上面的圆圈)来表示。按照UTF-8编码,Ångström符号由字节[0xE2,0x84,0xAB]表示,字符Å由字节[0xC3,0x85]表示,带有圆圈的A字符则由字节[0x41,0xCC,0x81]表示。当然,从用户的角度来看,在比较和排序时,两个Å字符应该是相等的,而无需关心其底层字节如何表示。

第一个问题并不如我们想象中的那么严重,因为Go语言中所有的UTF -8字节序列(即字符串)都是将字节映射到相同的码点。这意味着,例如,Go语言中字符或字符串常量中的é字符总是由相同的字节表示。当然,如果我们只考虑ASCII字符(即英语),这个问题就不会出现。即使当我们处理非ASCII字符时,这个问题也只有在当我们处理两个看起来一样但实际不同的字符时,或当我们从程序外部读取UTF-8字节时才会出现,读取的UTF-8字节具有合法UTF-8编码,但却不同于Go语言中的。如果这真的被证明是一个问题,我们可以编写一个自定义的标准化函数来确保,例如,总是将é字符以字节[0xC3,0xA9]表示(Go语言原生支持),而不是使用[0x65,0xCC,0x81](即e和´组合起来的字符)来表示。Unicode标准格式文档(unicode.org/reports/tr15)中有对标准化Unicode编码字符的解释。撰写本文时,Go语言标准库提供了一个实验性的标准化包(exp/norm)。

第一个问题只有在读取外部字符且与Go语言的码点-字节映射不同时才会发生,这个可以通过分离处理外部字符的代码来解决。该代码可以将读取到的字符在提供给程序之前将其标准化。

第二个问题是,有些情况下用户可能会希望把不同的字符视为相等的。例如,我们编写了一个具有文本搜索功能的程序且用户输入了单词“file”。当然,用户会希望搜索到所有包含“file”的结果;但他们也同样希望搜索到所有与“file”(即fi与le以连字符连接)匹配的结果。类似地,用户搜索“5”时可能希望可以搜索到“5”、“5”、“5”、甚至是“➄”。与第一个问题一样,可以通过使用一些标准工作来解决。

第三个问题是,有些字符的排序是与语言相关的。举例来说,瑞典语中ä排在z的后面,德国电话簿中ä被拼写成ae,而在德国字典中则被拼写成a。再举个例子,虽然在英文中我们在排序时将ø当作o,但在丹麦语和挪威语中它排在z的后面。在这方面有很多的规则,有时应用程序被不同国家的人使用(因此会有不同的排序规则),有时字符串中含有多种语言(如一些是西班牙语,其它是英语),某些字符(如箭头、修饰符以及数学符号)实际上就没有排序的意义,基于以上这些,排序规则本就是很复杂的。

从好的方面来说,Go语言对字符串逐字节比较的方式是借鉴于英文的ASCII排序方式。如果我们将要比较的字符串转换成全部小写或者全部大写,我们可以得到一个更自然的英语语言顺序。


目录


作者:Johnson
原创文章,版权所有,转载请保留原文链接。

发表评论

您的电子邮箱地址不会被公开。 必填项已用*标注