5

在 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));
}

但是长度需要可以正确地除以每个字符使用的字节数,所以最后一个字符总是正确呈现。

4

4 回答 4

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;
}

如果您必须处理代理对,它会变得有点棘手:(

于 2012-09-13T16:59:56.407 回答
1

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

于 2012-09-13T17:03:18.563 回答
1

虽然这是一个非常古老的问题,但我相信正确的方法是使用System.Globalization.StringInfo类的StringInfo.SubstringByTextElementsMethod。这样做的主要优点是 .NET 文档保证net461及更高版本,来电者注意事项StringInfo保证符合 Unicode 标准版本 8.0.0:

来电者须知

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

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

StringInfo课堂上,有一条注释说:

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

所以:

  1. 调用 ParseCombinigCharacters 以获取每个文本元素的起始索引
  2. 使用第一步提供的索引调用 SubstringByTextElements。
于 2020-04-09T16:23:11.140 回答
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;
}
于 2012-09-13T17:11:19.043 回答