iOS一点点 - TableView 拼音序排序(汉字转拼音、简繁体转换、日文转罗马音等)

相关链接

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" 应运而生,然后呵呵呵。具体看相关链接。

Cheat Sheet

任意支持语言转拉丁文:"Any-Latin" (中文转拼音、日文转罗马音) 简转繁:"Hans-Hant" (s 和 t 分别代表 Simplified 和 Traditional) 繁转简:"Hant-Hans" 平假名转片假名:"Hiragana-Katakana" 片假名转平假名:"Katakana-Hiragana"


到此为止,维持我继续探索的好奇心资源彻底枯竭了。。。本文告终。

再次附上 ICU transform ID 的相关页面:http://userguide.icu-project.org/transforms/general

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏蜉蝣禅修之道

Max-Min Fairness带宽分配算法

2106
来自专栏计算机视觉与深度学习基础

leetcode 6 ZigZag Conversion

The string "PAYPALISHIRING" is written in a zigzag pattern on a given number of...

2037
来自专栏机器学习从入门到成神

哥伦布编码

哥伦布编码解码 UINT GetUeValue(BYTE *pBuff, UINT nLen, UINT &nStartB...

1802
来自专栏数据结构与算法

BZOJ2115: [Wc2011] Xor(线性基)

第一行包含两个整数N和 M, 表示该无向图中点的数目与边的数目。 接下来M 行描述 M 条边,每行三个整数Si,Ti ,Di,表示 Si 与Ti之间存在 一条权...

691
来自专栏何俊林

如何学习OpenGL Shader开发?

shader也称着色器,着色器是运行在GPU上的小程序,着色器是一种C风格语言——GLSL。

2312
来自专栏walterlv - 吕毅的博客

出让执行权:Task.Yield, Dispatcher.Yield

发布于 2017-10-14 09:18 更新于 2018-02...

1181
来自专栏小文博客

蓝桥杯 C语言省赛 习题2 格子中输出

1584
来自专栏chenjx85的技术专栏

leetcode-201-数字范围按位与

给定范围 [m, n],其中 0 <= m <= n <= 2147483647,返回此范围内所有数字的按位与(包含 m, n 两端点)。

3692
来自专栏数据结构与算法

第二类斯特灵数学习笔记

设$S(n, m)$表示把$n$个不同的球放到$m$个相同的盒子里,且不允许盒子为空的方案数

964
来自专栏数值分析与有限元编程

可视化 | 一个三角形常应变单元后处理例子

昨天提到了应力云图,其实质是用不同的颜色填充等值线。有了结点的应力值,单元内任意一点的应力值是通过插值实现的。下面来看一个悬臂梁的综合后处理。 如图所示,一个悬...

2787

扫码关注云+社区

领取腾讯云代金券