2015-02-09 74 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

相關問題