原文: ICU Text Transforms in Cocoa
作者: Ole Begemann
译者:CocoaChina--oOatuo(微博)
ICU的字符转换很酷 。 ICU库 提供了一系列的强大的的文本转换,这在需要处理用户输入,尤其是需要处理除英语以外的语言和非拉丁文字时非常有用。举个例子,你可以把一段简体中文转码成拉丁字符,并且去掉字母上读音符号、其他变音符号和隐藏字符,最后转化成小写,以便你的数据库搜索API可以识别,而所有的这些转换,用一句代码就可以实现。
在Apple的平台上,字符串转换一直以来是通过Core Foundation的 CFStringTransform函数 实现。更多的关于该API的内容,推荐阅读Matt Thompson在 NSHipster上的一篇非常不错的文章 。
随着iOS 9和OS X 10.11的发布,字符串转换被整合到了Foundation框架中。虽然还没有关于 NSString 的新方法stringByApplyingTransform(_:reverse:)的文档介绍,但是CFStringTransform文档已经对它进行了说明,而且Nate Cook在 这篇NSHipster的文章 中也举了一些例子。下面是从中文转换到拉丁文的代码:
import Foundation let shanghai = "上海" shanghai.stringByApplyingTransform(NSStringTransformToLatin, reverse: false) // returns "shàng hǎi”
看起来还不错,Apple现在提供16中固定的转换,它们大部分的都是字符转码,还有一些其他方法可以去掉输入字符串的组合标记和变音符号、转换为码点以及转换为标准的 Unicode 形式。另外,大多数的转换都是可逆的,只要设置下 stringByApplyingTransform 的第二个参数。这非常强大了,尤其是当你做链式调用变换操作的时候(比如先转码再去除变音符号)。
尽管在 CFStringTransform 文档和 NSHipster 的文章中都提到过,但我之前一直没意识到可以像ICU这样自由转换。ICU 自定义了一套语法来表示转换,如果你将符合这语法的字符串作为参数传给 stringByApplyingTransform 或 CFStringTransform,它就会识别!比如这样:
// Convert non-ASCII characters to ASCII, // convert to lowercase, delete spaces "Café au lait".stringByApplyingTransform( "Latin-ASCII; Lower; [:Separator:] Remove;", reverse: false) // returns “cafeaulait"
这篇ICU用户指南写的不错,里面包含了很多例子。强烈推荐你学习下。这里是我自己的一些例子:
仅将元音字母转换成小写。方括号定义了了一个过滤器。变换规则只会应用在符合过滤条件的字符上。
转换成拉丁,再转换成ASCII,最后转换成小写。用分号将不同规则隔开。拉丁转 ASCII时会移除变音符号以及会试着将ASCII范围之外的符号和标点转换成ASCII中与之最接近的值。
删除标点。删除规则很强大。上面的例子都是用方括号加一些字符串规则来表示过滤条件,但过滤器也可以像这个例子一样,由 Unicode 字符类 给出
删除所有非字母字符。使用 ^ 来取反。
把标点转换成印刷体。Publish规则可以直接将标点符号转换成对应的印刷体。
转换成十六进制表达式。支持多种格式,默认是Java格式。注意Java输出成UTF-16的字符单元(表情会分两部分解码),而其他的格式输出码点。
想象一下,你自己去实现上面的转换是多么蛋疼。
自由转换规则是我从 Florian 和 Daniel 的 Core Data 书 上学来的。他们介绍了如何把用户输入的搜索词标准化后再提交到数据库。这样既可以有效提升搜索性能,也能让搜索结果更加准确。