2015-02-09 24 views
1

我需要计算一个子字符串将被转换为UTF8字节数组的大小(以字节为单位)。这需要发生,而实际上并没有对该子字符串进行转换。不幸的是,我正在使用的字符串非常大,我必须小心,不要在内存中创建另一个大字符串(或字节数组)。计算UTF8转换所需字节数的正确方法是什么?

Encoding.UTF8对象上有一个名为GetByteCount的方法,但我没有看到一个重载,它不需要将字符串复制到一个字节数组中。这不适用于我:

Encoding.UTF8.GetByteCount(stringToCount.ToCharArray(), startIndex, count); 

因为stringToCount.ToCharArray()将创建我的字符串的副本。

这就是我现在所拥有的:

public static int CalculateTotalBytesForUTF8Conversion(string stringToCount, int startIndex, int endIndex) 
{ 
    var totalBytes = 0; 
    for (int i = startIndex ; i < endIndex; i++) 
    totalBytes += Encoding.UTF8.GetByteCount(new char[] { stringToCount[i] }); 

    return totalBytes; 
} 

的GetByteCount方法似乎并不不得不采取在短短的焦炭的能力,所以这是我在妥协。

这是确定一个字符串的字节数正确的方式,转换为UTF-8之后,实际上并没有这样做的转换?还是有更好的方法来做到这一点?

+1

看看@ http://stackoverflow.com/questions/8511490/calculating-length-in-utf-8-of-java-string-without-actually-encoding-it(c#在char上有ishighsurrogate) – 2015-02-09 16:35:55

回答

1

似乎没有成为这样一个内置的方法,让你既可以自己分析字符或做那种你在上面做的事情。我唯一会建议 - 重用一个char [1]数组,而不是建立在每次迭代的新数组。这里有一个扩展方法,可以很好地使用内置方法。

public static class EncodingExtensions 
{ 
    public static int GetByteCount(this Encoding encoding, string s, int index, int count) 
    { 
     var output = 0; 
     var end = index + count; 
     var charArray = new char[1]; 
     for (var i = index; i < end; i++) 
     { 
      charArray[0] = s[i]; 
      output += Encoding.UTF8.GetByteCount(charArray); 
     } 
     return output; 
    } 
} 
+0

抓住不重新分配该char []。这应该为我节省数百万个实例。 – Grandpappy 2015-02-09 16:47:09

+0

当然有*内置的方法可以做到这一点,但它们并不像调用一样简单。 – 2015-02-09 17:01:20

1

因此,有不需要主叫用户首先创建一个字符数组的过载:Encoding.GetByteCount Method (Char*, Int32)

的问题是,这不是一个符合CLS的方法,并会要求你做一些外来编码:

public static unsafe int CalculateTotalBytesForUTF8Conversion(
    string stringToCount, 
    int startIndex, 
    int endIndex) 
{ 
    // Fix the string in memory so we can grab a pointer to its location. 
    fixed (char* stringStart = stringToCount) 
    { 
     // Get a pointer to the start of the substring. 
     char* substring = stringStart + startIndex; 

     return Encoding.UTF8.GetByteCount(substring, endIndex - startIndex); 
    } 
} 

关键的东西这里要注意:

  • 的方法有被标记为不安全的,因为我们正在处理指针和直接内存操作。
  • 字符串是为了防止运行时移动它固定在呼叫持续时间 - 它为我们提供了一个恒定的位置指向,但它可以防止运行时做内存优化。

您应该考虑在此方法上进行彻底的性能分析,以确保它比仅将字符串复制到数组时更好的性能分布。

基本分析(执行我的台式机上按顺序算法控制台应用程序)示出了这种方法执行〜比遍历字符串或将其转换成字符阵列快35倍的比特。

  • 使用指针:〜86ms
  • 循环过串:〜2957ms
  • 转换为字符数组:〜3156ms

把这些数字与一撮盐,并且还考虑其他因素除了执行速度之外,如长期执行开销(即在服务进程中)或内存使用情况。

+0

在我正在处理的代码中,毫无疑问,我无法将字符串安全地复制到字节数组,而不会冒着OutOfMemory异常的风险。所以我不太关心它会提供的性能改进,如果它会导致一个非常大的字符串(约150 MB)的任何问题。我知道有一个很大的字符串是很糟糕的,但我目前没有选择。 – Grandpappy 2015-02-09 17:05:33

+0

作为一个方面说明,这段代码会抛出一个错误:不能分配给'substring',因为它是一个'固定变量'。所以我创建了“char * startOfSubstring = substring + startIndex;”在固定括号内,并用于GetByteCount。 – Grandpappy 2015-02-09 17:09:38

+0

你是对的找到那个错误 - 我会纠正它。 – 2015-02-09 17:47:05

相关问题