【问题标题】:Emoji conversion to a specific string representation表情符号转换为特定的字符串表示
【发布时间】:2018-07-12 16:06:42
【问题描述】:

目前我正在使用一个名为 Emoji 的元组 HashSet 将 Emoji 替换为字符串表示形式,例如,炸弹的 emoji 变为 U0001F4A3。转换通过

完成
Emoji.Aggregate(input, (current, pair) => current.Replace(pair.Item1, pair.Item2));

按预期工作。

但是,我试图在不使用 2600 多个项目的预定义列表的情况下实现相同的目标。有没有人已经实现了这样的事情,即字符串中的表情符号被替换为不带 \ 的对应符号?

例如:

"This string contains the unicode character bomb (????)"

变成

"This string contains the unicode character bomb (U0001F4A3)"

【问题讨论】:

  • 您想用十六进制表示替换“U+FFFF 以上的每个字符”吗?如果是这样,那相对简单。如果不是那么简单(要么是因为 BMP 中有要替换的字符,要么是因为 BMP 中没有你不想要替换的字符),那就更难了。
  • 可以的。
  • 好的,会写答案的。

标签: c# .net unicode


【解决方案1】:

听起来您很乐意将不在basic multi-lingual plane 中的任何字符替换为其十六进制表示。执行此操作的代码有点冗长,但非常简单:

using System;
using System.Text;

class Test
{
    static void Main()
    {
        string text = "This string contains the unicode character bomb (\U0001F4A3)";
        Console.WriteLine(ReplaceNonBmpWithHex(text));
    }

    static string ReplaceNonBmpWithHex(string input)
    {
        // TODO: If most string don't have any non-BMP characters, consider
        // an optimization of checking for high/low surrogate characters first,
        // and return input if there aren't any.
        StringBuilder builder = new StringBuilder(input.Length);
        for (int i = 0; i < input.Length; i++)
        {
            char c = input[i];
            // A surrogate pair is a high surrogate followed by a low surrogate
            if (char.IsHighSurrogate(c))
            {
                if (i == input.Length -1)
                {
                    throw new ArgumentException($"High surrogate at end of string");
                }
                // Fetch the low surrogate, advancing our counter
                i++;
                char d = input[i];
                if (!char.IsLowSurrogate(d))
                {
                    throw new ArgumentException($"Unmatched low surrogate at index {i-1}");
                }
                uint highTranslated = (uint) ((c - 0xd800) * 0x400);
                uint lowTranslated = (uint) (d - 0xdc00);
                uint utf32 = (uint) (highTranslated + lowTranslated + 0x10000);
                builder.AppendFormat("U{0:X8}", utf32);
            }
            // We should never see a low surrogate on its own
            else if (char.IsLowSurrogate(c))
            {
                throw new ArgumentException($"Unmatched low surrogate at index {i}");
            }
            // Most common case: BMP character; just append it.
            else
            {
                builder.Append(c);
            }
        }
        return builder.ToString();
    }
}

请注意,根据 Yury 的回答,不会尝试处理多个字符一起使用的情况。它会将每个修饰符/emoji/secondary-char 替换为单独的 UXXXXXXXX 部分。

【讨论】:

  • 感谢 Daisy 已经提供了这段代码。非常感激。我将使用它作为我编码的基础。我注意到并不是所有的表情符号都被翻译了。例如皱着眉头的脸。
  • @KrisvanderMast:你是​​说 U+2639 吗? (fileformat.info/info/unicode/char/2639/index.htm) 如果是这样,那是在 BMP 中,这就是它没有被替换的原因。您可能需要包含“额外”字符(或可能的代码块)的列表。我认为这可能归结为你认为的表情符号。
【解决方案2】:

恐怕你在这里有一个错误的假设。表情符号不仅仅是一个“特殊的 Unicode 字符”。特定表情符号的实际长度可以是连续 4 个或更多字符。例如:

  • 表情符号本身
  • 零宽度接缝
  • 辅助字符(如毕业帽或麦克风)
  • 性别修饰符(男人或女人)
  • 肤色调节剂(菲茨帕特里克量表)

因此,您肯定应该考虑到可变长度。

例子:

【讨论】:

  • 是的,我知道这一点。在进行这项工作之前,我编写了 2600 多个单元测试,每个 emoji 一个,并发现 (wo)men 以某种语气摔跤提供不同的字符而不是一个,而威尔士的国旗被认为是一个,但是当你看看什么是前提是它是由大量 Unicode 字符组成的。主要目的是“翻译”它们,以便我们可以在 NLP 引擎中使用它们,该引擎默认情况下不理解表情符号(至少是我们目前使用的服务)。
猜你喜欢
  • 2019-05-20
  • 2021-10-04
  • 1970-01-01
  • 1970-01-01
  • 2016-03-22
  • 2021-02-23
  • 2018-12-15
  • 1970-01-01
  • 2019-04-22
相关资源
最近更新 更多