Introduction to ICU General Transforms Transform Rule Tutorial 使用ICU进行拼音转汉字暂时似乎也许可能是不太行的
前阵子做了个通讯录的功能,遇到了中文按拼音序排序的问题。然后在某个页面发现 Foundation 框架中提供了一个 func stringByApplyingTransform(_:reverse:)
可用于汉字转拼音。所以这文章叫 iOS 汉字转拼音可能更加合适点,拼音序排序只是个展示用处的简单范例。。。
虽然说是 iOS ,但在本文后半部分的扩展中,我们还简单了解了这个方法背后的一个叫 ICU 的项目,使得 C/C++ 与 Java 语言的开发者在遇到类似问题时也可以借鉴本文内容。
同样的,日文转罗马音等需求也可以用同样方式实现。
playground 中复制如下代码,创建一个基本的 TableView 。
import UIKit
class TableViewDataSource:NSObject, UITableViewDataSource {
// 名字为随机生成,如有雷同纯属巧合
var datasource = [["pinyin":"#", "chinese":"唐博超"],
["pinyin":"#", "chinese":"潘胤祥"],
["pinyin":"#", "chinese":"李烨霖"],
["pinyin":"#", "chinese":"邱子轩"],
["pinyin":"#", "chinese":"廖健雄"],
["pinyin":"#", "chinese":"朱伟宸"],
["pinyin":"#", "chinese":"蔡鸿煊"],
["pinyin":"#", "chinese":"侯绍齐"]]
override init() {
super.init()
tableview.registerClass(UITableViewCell.self, forCellReuseIdentifier: "cell")
//TODO: 对姓名按拼音排序
}
func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return datasource.count
}
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell = tableview.dequeueReusableCellWithIdentifier("cell", forIndexPath: indexPath)
cell.textLabel?.text = datasource[indexPath.row]["chinese"]! + datasource[indexPath.row]["pinyin"]!
return cell
}
}
let tableview = UITableView(frame: CGRect(x: 0, y: 0, width: 200, height: 350))
let datasource = TableViewDataSource()
tableview.dataSource = datasource
tableview.reloadData()
最后一行 reloadData 后, tableView 状态如下图:
然后用以下代码替换 //TODO: 对姓名按拼音排序
这一行:
for i in 0..<datasource.count {
datasource[i]["pinyin"] = datasource[i]["chinese"]!.stringByApplyingTransform(NSStringTransformToLatin, reverse: false)?.uppercaseString ?? "#"
}
datasource.sortInPlace({ $0["pinyin"] < $1["pinyin"] })
其中关键就是 stringByApplyingTransform(_:reverse:)
,我们还提供了 NSStringTransformToLatin
作为第一个变量,指定将任意字串转为对应的拉丁文,即可依此进行排序。结果如下图:
拼音序排序目的达成
目的似乎是达到了,但这个神秘兮兮的方法(找不到多少它的文档)到底是个什么原理,还有没有什么高级的用法呢?,我们 Command+单击
继续追本溯源一下,看到了一段这样的注释:
/* Perform string transliteration.
The transformation represented by transform is applied to the receiver.
reverse indicates that the inverse transform should be used instead, if it exists.
Attempting to use an invalid transform identifier or reverse an irreversible transform will return nil;
otherwise the transformed string value is returned (even if no characters are actually transformed).
You can pass one of the predefined transforms below (NSStringTransformLatinToKatakana, etc),
or any valid ICU transform ID as defined in the ICU User Guide.
Arbitrary ICU transform rules are not supported.
*/
- (nullable NSString *)stringByApplyingTransform:(NSString *)transform reverse:(BOOL)reverse NS_AVAILABLE(10_11, 9_0); // Returns nil if reverse not applicable or transform is invalid
/* 进行字符串的翻译工作。
由 transform 参数表示的映射过程将会被应用到消息的接受者(我们的待翻译字符串)上。
reverse 参数表示将应用相反的映射进行翻译,如果对应的反向映射存在的话。
使用无效的映射标识,或尝试反转一个不可反转的映射,将返回 nil。
其他情况下,将返回映射后的字符串内容(即使没有任何字符真正改变过)
你可以给出一个下面预定义好的映射(比如我们之前用于把汉字转为拉丁文的 NSStringTransformToLatin,还有一个 NSStringTransformMandarinToLatin 但实际使用中我没有发现什么区别)
*** 或者任意 ICU User Guide 中定义的有效的 ICU 映射 ID 。 ***
不支持自定义(Arbitrary 不确定翻译正确性)的 ICU 映射规则
*/
注释中混进来的 ICU 跟翻译有什么关系?继续顺藤摸瓜:
International Components for Unicode ICU is a mature, widely used set of C/C++ and Java libraries providing Unicode and Globalization support for software applications. ICU is widely portable and gives applications the same results on all platforms and between C/C++ and Java software.
ICU(International Components for Unicode)是一组成熟的、广泛使用的 C/C++ 和 Java 库。
为软件应用提供了 Unicode 和全球化支持。
ICU 被广泛移植到了不同的平台,并且在所有平台上、 Java 和 C/C++ 语言之间,都能给出相同的结果。
然后是 Transform 部分:
Transforms are used to process Unicode text in many different ways. Some include case mapping, normalization, transliteration and bidirectional text handling.
Transform 被用于以许多不同的方式处理 Unicode 文本。Some include case mapping, normalization, transliteration and bidirectional text handling.
第二句太多不确定的词,不翻译了,但可以看出我们用到的 正是Transform 这里的功能。
看来我们这里用到的这个方法其实是苹果在 iOS 平台中也移植或实现了 ICU 的部分功能!纯粹因为好奇验证一下,我查阅了 ICU User Guide ,并找到了与 NSStringTransformToLatin
对应的 ICU transform ID 将其替换掉,看看结果如何:
//NSStringTransformToLatin 对应 "Any-Latin"
datasource[i]["pinyin"] = datasource[i]["chinese"]!.stringByApplyingTransform("Any-Latin", reverse: false)?.uppercaseString ?? "#"
结果完全一致,原谅我用了同一张图,但结果确实一致。
玩到这里突发奇想,汉字转拼音可以,拼音转汉字呢?于是 "Latin-Hans" 应运而生,然后呵呵呵。具体看相关链接。
任意支持语言转拉丁文:"Any-Latin" (中文转拼音、日文转罗马音) 简转繁:"Hans-Hant" (s 和 t 分别代表 Simplified 和 Traditional) 繁转简:"Hant-Hans" 平假名转片假名:"Hiragana-Katakana" 片假名转平假名:"Katakana-Hiragana"
到此为止,维持我继续探索的好奇心资源彻底枯竭了。。。本文告终。
再次附上 ICU transform ID 的相关页面:http://userguide.icu-project.org/transforms/general