原文: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 書上學來的。他們介紹了如何把用戶輸入的搜索詞標准化後再提交到數據庫。這樣既可以有效提升搜索性能,也能讓搜索結果更加准確。