用于拉丁语,中文,西里尔语等的子串UTF-8

时间:2012-09-13 16:53:25

标签: c# .net utf-8

在Windows Phone上,我想将任何给定字符串子串到相当于100个ASCII字符的长度。

String.Length显然没用,因为中文字符串每个字符使用3个字节,丹麦字符串每个字符使用2个或4个字节,俄语字符串每个字符使用4个字节。

唯一可用的编码是UTF-8和UTF-16。那我该怎么办?

这个想法是这样的:

private static string UnicodeSubstring(string text, int length)
{
    var bytes = Encoding.UTF8.GetBytes(text);

    return Encoding.UTF8.GetString(bytes, 0, Math.Min(bytes.Length, length));
}

但是长度需要使用每个字符使用的字节数正确分割,因此 last 字符始终可以正确呈现。

4 个答案:

答案 0 :(得分:6)

一个选项是简单地浏览字符串,计算每个字符的字节数。

如果您知道不需要处理BMP之外的字符,这很简单:

public string SubstringWithinUtf8Limit(string text, int byteLimit)
{
    int byteCount = 0;
    char[] buffer = new char[1];
    for (int i = 0; i < text.Length; i++)
    {
        buffer[0] = text[i];
        byteCount += Encoding.UTF8.GetByteCount(buffer);
        if (byteCount > byteLimit)
        {
            // Couldn't add this character. Return its index
            return text.Substring(0, i);
        }
    }
    return text;
}

如果你必须处理代理人对,那就变得有点棘手了:(

答案 1 :(得分:1)

一种选择是简单地将“字符”(包括代理对,如果你需要支持它们)添加到结果字符串中,看看它是否被转换成你想要的正确数字。

答案 2 :(得分:1)

尽管这是一个非常老的问题,但我认为正确的方法是使用System.Globalization.StringInfo类的StringInfo.SubstringByTextElements Method。这样做的主要优点是对net461及更高版本的.NET文档保证,StringInfo的{​​{3}}保证符合Unicode标准版本8.0.0:

给来电者的记录

内部,StringInfo类的方法调用 CharUnicodeInfo类确定字符的方法 类别。从.NET Framework 4.6.2开始,字符 分类基于Unicode标准版本8.0.0。对于 NET Framework 4.6.1至.NET Framework 4,它基于 Unicode标准版本6.3.0。在.NET Core中,它基于 Unicode标准版本8.0.0。

现在,鉴于Microsoft Docs上没有有关如何调用它的示例,您如何实际调用SubstringByTextElements?

StringInfo类中,有一个注释说:

  • 通过调用ParseCombiningCharacters方法来检索包含每个文本元素的起始索引的数组。然后,您可以通过将这些索引传递给SubstringByTextElements方法来检索单个文本元素。

所以:

  1. 调用ParseCombinigCharacters以获得每个文本元素的起始索引
  2. 使用第一步提供的索引调用SubstringByTextElements。

答案 3 :(得分:0)

还有一个想法是检查最后一个字符是否为Unicode Replace Character,并删除一个字符,直到它被正确呈现。

private static string UnicodeSubstring(string text, int length)
{
    var bytes = Encoding.UTF8.GetBytes(text);
    var result = Encoding.UTF8.GetString(bytes, 0, Math.Min(bytes.Length, length));

    while ('\uFFFD' == result[result.Length - 1])
    {
        result = result.Substring(0, result.Length - 1);
    }

    return result;
}