背景
????前些陣子遇到一個需求,一個文本剪輯器,發(fā)布時需要統(tǒng)計除 Emoji 外的字數(shù),于是求助度娘,以 ”NSString 是否包含 Emoji“ 為關鍵字找到不同的文章都給出了一模一樣的解決方案,但實際測試中,這個方案隨著 iOS 版本的更迭早已不再適用
解決方案
????在這篇文章里面: iOS - 判斷 NSString 字符串是否包含 Emoji
原理
????想做 Emoji 判斷首先需要要有兩個前置的知識儲備,Unicode 編碼方式和原理,以及 NSString 和 Unicode 的關系。
Unicode
????限于篇幅,關于 Unicode 的簡介和發(fā)展歷程可以參考我的這篇文章:Unicode 簡介與發(fā)展歷程,里面有著詳細的 UTF 編碼原理介紹。
????此外,網(wǎng)絡上面也有著許多和 Unicode 相關的大佬們的文章可以閱讀。Unicode 官網(wǎng)里面更有著非常詳細的介紹和細節(jié)。
NSString 與 UTF
????在了解了 Unicode 和 UTF 編碼原理之后,只需要再了解 NSString 使用了那種編碼方式就很容易找出解決方案。而 NSString 的編碼方式在 NSString.h 的頭文件中有明確的說明:
/* The unichar type represents a single UTF-16 code unit in an NSString. Although many human-readable characters are representable with a single unichar, some such as Emoji may span multiple unichars. See discussion above.
*/
typedef unsigned short unichar;
????在明確了 NSString 使用 UTF-16 的編碼方式之后,結(jié)合 UTF-16 的編碼原理,可以得到 NSString 和碼點之間的互相的轉(zhuǎn)換關系如下:
/*
Nsstring 轉(zhuǎn)換為碼點
*/
- (int)stringToCodePoint:(NSString *)string {
const unichar hs = [string characterAtIndex:0];
if (0xd800 <= hs && hs <= 0xdbff) {
if (string.length > 1) {
const unichar ls = [string characterAtIndex:1];
const int codepoint = (((int)hs - 0xd800) * 0x400) + ((int)ls - 0xdc00) + 0x10000;
return codepoint;
} else {
return 0;
}
} else {
return (int)hs;
}
}
/*
碼點轉(zhuǎn)換為 NSString
*/
- (NSString *)stringFromCodePoint:(int)codePoint {
if (codePoint <= 0xFFFF)
{
return [[NSString alloc] initWithBytes:&codePoint length:sizeof(codePoint) encoding:NSUTF8StringEncoding];
}
else if (0x10000 <= codePoint && codePoint <= 0x10FFFF)
{
int symbol = ((((0x808080F0 | (codePoint & 0x3F000) >> 4) | (codePoint & 0xFC0) << 10) | (codePoint & 0x1C0000) << 18) | (codePoint & 0x3F) << 24);
return [[NSString alloc] initWithBytes:&symbol length:sizeof(symbol) encoding:NSUTF8StringEncoding];
}
else
{
return nil;
}
}
????了解了 NSString 和 Unicode 碼點之間的轉(zhuǎn)換關系,就可以理解上面解決方案里面提供的方案。
題外話
????實際上,Emoji 的編碼方式遠比我們想象的要復雜得多,盡管上述的解決方案可以解決問題,但是在做碼點和 NSString 的互相轉(zhuǎn)化過程中,發(fā)現(xiàn) Emoji 除了有單碼點表示的方法之外,還有多碼點組合字符的形式。
????這篇文章里面會詳細的介紹 Unicode 與 Emoji 的組合字:Unicode 和 Emoji 中的組合字符