在 Cocoa 中实现 ICU 文本变换

作者:Ole Begemann,原文链接,原文日期:2016-01-03
译者:aaaron7;校对:numbbbbb;定稿:Cee

ICU 的字符串变换很酷。ICU 库提供了一整套强大的文本变换功能,在处理用户输入、特别是当你的程序需要处理一些英语之外的语言或者非拉丁字符时非常有用。举个例子,你可以把一段简体中文转码成拉丁字符,同时清除音调符号、修饰符和隐藏字符,最后全部转换成小写,使其成为可以被你的数据库搜索 API 识别的字符串,而所有这些变换,只要一行代码就可完成。

在 Apple 的平台中,字符串变换一直以来都是通过 Core Foundation 的 CFStringTranform 函数来实现。Mattt Thompson 在 NSHipster 上对该 API 有非常棒的介绍,推荐阅读。

随着 iOS 9 和 OS X 10.11 的发布,字符串变换被整合到了 Foundation 框架中。虽然在文档中还没有介绍 NSString 的新方法 stringByApplyingTransform(_:reverse:),但是 CFStringTransform 文档已经对它进行了说明,而且 Nate Cook 在 这篇 NSHipster 的文章中也展示了一些具体的例子。下面的代码演示了如何实现中文到拉丁字符的转换:

import Foundation
let shanghai = "上海"
shanghai.stringByApplyingTransform(NSStringTransformToLatin,
    reverse: false) // 返回 "shàng hǎi"

看起来还不错。Apple 提供了 16 种固定的变换,绝大多数都是字符转码(译者注:Script Transliterations,指的是把其中一种语言的字符变换成另一种语言的字符。详情可参考这里),其中一些方法允许你清除输入字符的组合标记符号和读音符号、转换为码点以及转换为标准的 Unicode 形式。另外,绝大多数变换都是可逆的,只要设置 stringByApplyingTransform(_:reverse:) 函数的第二个参数即可。特别是做链式调用变换操作的时候,这显得非常强大(比如首先转码,然后去除变音符号)。

自由变换

有一个牛逼功能,CFStringTransform 文档和 NSHipster 的文章中都有提到,但我之前一直没意识到,它就是自由变换。 ICU 自己定义了一套语法来表示变换,如果你把遵循这套语法的字符串作为参数传给 stringByApplyingTransform(_:reverse:) ,它就可以识别!比如这样:

// 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 用户手册写的非常好,并且包含很多例子。强烈推荐你学习一下。这里是几个我做的例子:

转换成小写。

输入 变换 结果
HELLO WORLD Lower hello world

仅转换元音字母为小写。 方括号定义了一个过滤器,表示只对满足过滤条件的字符应用变换规则。

输入 变换 结果
HELLO WORLD [AEIOU] Lower HeLLo WoRLD

先转成拉丁,再转成 ASCII,最后转换成小写。 用分号把不同的转换规则隔开。拉丁到 ASCII 这一步会移除变音符以及会把 ASCII 码范围之外的字符和标点符号转换成 ASCII 中与之最为接近的版本。

输入 变换 结果
上海 Any-Latin; Latin-ASCII; Lower shang hai
København Any-Latin; Latin-ASCII; Lower kobenhavn
กรุงเทพมหานคร Any-Latin; Latin-ASCII; Lower krungthephmhankhr
Αθήνα Any-Latin; Latin-ASCII; Lower athena
“Æ « © 1984” Any-Latin; Latin-ASCII; Lower "ae << (c) 1984"

删除标点。 删除规则非常强大。上面的例子都是用方括号加一些字符串规则来表示过滤条件,但过滤器也可以像这个例子一样,由 Unicode 字符类给出。

输入 变换 结果
“Make it so,” said Picard. [:Punctuation:] Remove Make it so said Picard

删除所有非字母字符。使用 ^ 来对字符串做过滤。

输入 变换 结果
5 plus 6 equals 11 👍! [:^Letter:] Remove plusequals

把标点符号转换成印刷体。Publishing 规则可以直接把标点符号转换成对应的印刷版本。

输入 变换 结果
"How's it going?" Publishing “How’s it going?”

转换为十六进制表示法。支持很多种格式。默认是 Java 格式。需要注意的是,这里 Java 输出的是 UTF-16 字符单元(表情分为两部分编码),而其他格式则是输出码点。

输入 变换 结果
😃! Hex \uD83D\uDE03\u0021
😃! Hex/Java \uD83D\uDE03\u0021
😃! Hex/Unicode U+1F603U+0021
😃! Hex/Perl \x{1F603} \x{21}
😃! Hex/XML 😃!

转换成多种标准化的形式。

输入 变换 结果
é NFD; Hex/Unicode U+0065U+0301
é NFC; Hex/Unicode U+00E9
2⁸ NFKD 28
2⁸ NFKC 28

想象一下,自己实现上述转换方法多么蛋疼……

自由变换的知识我是从 Florian 和 Daniel 写的那本 Core Data 里学来的。他们介绍了如何把用户输入的搜索词标准化后再提交到数据库。 这样既可以有效提升搜索性能,也能让搜索的结果更加准确。

本文由 SwiftGG 翻译组翻译,已经获得作者翻译授权,最新文章请访问 http://swift.gg

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 199,064评论 5 466
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 83,606评论 2 376
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 146,011评论 0 328
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 53,550评论 1 269
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 62,465评论 5 359
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 47,919评论 1 275
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,428评论 3 390
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,075评论 0 254
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,208评论 1 294
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,185评论 2 317
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,191评论 1 328
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 32,914评论 3 316
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,482评论 3 302
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,585评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,825评论 1 255
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,194评论 2 344
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 41,703评论 2 339

推荐阅读更多精彩内容