美文网首页
iOS - NSString 与 Emoji

iOS - NSString 与 Emoji

作者: hackswang | 来源:发表于2021-10-28 10:01 被阅读0次

    背景

        前些阵子遇到一个需求,一个文本剪辑器,发布时需要统计除 Emoji 外的字数,于是求助度娘,以 ”NSString 是否包含 Emoji“ 为关键字找到不同的文章都给出了一模一样的解决方案,但实际测试中,这个方案随着 iOS 版本的更迭早已不再适用

    解决方案

        在这篇文章里面: iOS - 判断 NSString 字符串是否包含 Emoji

    原理

        想做 Emoji 判断首先需要要有两个前置的知识储备,Unicode 编码方式和原理,以及 NSString 和 Unicode 的关系。

    Unicode

        限于篇幅,关于 Unicode 的简介和发展历程可以参考我的这篇文章:Unicode 简介与发展历程,里面有着详细的 UTF 编码原理介绍。

        此外,网络上面也有着许多和 Unicode 相关的大佬们的文章可以阅读。Unicode 官网里面更有着非常详细的介绍和细节。

    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 的编码方式之后,结合 UTF-16 的编码原理,可以得到 NSString 和码点之间的互相的转换关系如下:

    /*
     Nsstring 转换为码点
     */
    - (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;
        }
    }
    
    /*
     码点转换为 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 码点之间的转换关系,就可以理解上面解决方案里面提供的方案。

    题外话

        实际上,Emoji 的编码方式远比我们想象的要复杂得多,尽管上述的解决方案可以解决问题,但是在做码点和 NSString 的互相转化过程中,发现 Emoji 除了有单码点表示的方法之外,还有多码点组合字符的形式。

        这篇文章里面会详细的介绍 Unicode 与 Emoji 的组合字:Unicode 和 Emoji 中的组合字符

    相关文章

      网友评论

          本文标题:iOS - NSString 与 Emoji

          本文链接:https://www.haomeiwen.com/subject/rblwnltx.html