[英]How to print .NET String.Format space character on a regular string?
[英]Space in a .NET string returned by string.Format does not match space declared in source code - multiple representations?
string.Format返回的字符串似乎使用了一些奇怪的編碼。 與源代碼中聲明的字符串中包含的空格相比,格式字符串中包含的空格使用不同的字節值表示。
以下測試用例演示了該問題:
[Test]
public void FormatSize_Regression()
{
string size1023 = FileHelper.FormatSize(1023);
Assert.AreEqual("1 023 Bytes", size1023);
}
失敗:
String lengths are both 11. Strings differ at index 1. Expected: "1 023 Bytes" But was: "1 023 Bytes" ------------^
FormatSize方法:
public static string FormatSize(long size)
{
if (size < 1024)
return string.Format("{0:N0} Bytes", size);
else if (size < 1024 * 1024)
return string.Format("{0:N2} KB", (double)((double)size / 1024));
else
return string.Format("{0:N2} MB", (double)((double)size / (1024 * 1024)));
}
在Assert行上設置斷點時從VS立即窗口:
size1023
"1 023 Bytes"
System.Text.Encoding.UTF8.GetBytes(size1023)
{byte[12]}
[0]: 49
[1]: 194 <--------- space is 194/160 here? Unicode bytes indicate that space should be the 160. What is the 194 then?
[2]: 160
[3]: 48
[4]: 50
[5]: 51
[6]: 32
[7]: 66
[8]: 121
[9]: 116
[10]: 101
[11]: 115
System.Text.Encoding.UTF8.GetBytes("1 023 Bytes")
{byte[11]}
[0]: 49
[1]: 32 <--------- space is 32 here
[2]: 48
[3]: 50
[4]: 51
[5]: 32
[6]: 66
[7]: 121
[8]: 116
[9]: 101
[10]: 115
System.Text.Encoding.Unicode.GetBytes(size1023)
{byte[22]}
[0]: 49
[1]: 0
[2]: 160 <----------- 160,0 here
[3]: 0
[4]: 48
[5]: 0
[6]: 50
[7]: 0
[8]: 51
[9]: 0
[10]: 32
[11]: 0
[12]: 66
[13]: 0
[14]: 121
[15]: 0
[16]: 116
[17]: 0
[18]: 101
[19]: 0
[20]: 115
[21]: 0
System.Text.Encoding.Unicode.GetBytes("1 023 Bytes")
{byte[22]}
[0]: 49
[1]: 0
[2]: 32 <----------- 32,0 here
[3]: 0
[4]: 48
[5]: 0
[6]: 50
[7]: 0
[8]: 51
[9]: 0
[10]: 32
[11]: 0
[12]: 66
[13]: 0
[14]: 121
[15]: 0
[16]: 116
[17]: 0
[18]: 101
[19]: 0
[20]: 115
[21]: 0
問題:這怎么可能?
我懷疑你當前的文化正在使用一個有趣的“千位”分隔符--U + 00A0,這是一個不間斷的空格字符。 這不是一個完全不合理的千位分隔符,說實話......這意味着你不應該得到這樣的文字顯示:
The size of the file is 1
023 bytes.
相反,你會得到
The size of the file is
1 023 bytes.
在我的盒子上,我得到了“1,023”。 您希望FormatSize
方法使用當前文化還是特定文化? 如果它是當前的文化,你應該讓你的單元測試指定文化。 我有幾個用於此的包裝器方法:
internal static void WithInvariantCulture(Action action)
{
WithCulture(CultureInfo.InvariantCulture, action);
}
internal static void WithCulture(CultureInfo culture, Action action)
{
CultureInfo original = Thread.CurrentThread.CurrentCulture;
try
{
Thread.CurrentThread.CurrentCulture = culture;
action();
}
finally
{
Thread.CurrentThread.CurrentCulture = original;
}
}
所以我可以跑:
WithInvariantCulture(() =>
{
// Body of test
};
等等
如果你想測試你得到的確切字符串,你可以使用:
Assert.AreEqual("1\u00A0023 Bytes", size1023);
UTF8中的Unicode 160 不是由單個字節160表示,而是由兩個字節表示。 沒有檢查,我打賭那些是194 + 160。
實際上,超過127的任何Unicode代碼點都由多個字節表示。
我猜你的CultureInfo使用一個不間斷的空間(160)作為千個分組分隔符,而不是像你自己鍵入的簡單空格(32)。
194,160是代碼點160的utf8:非破壞空間 -
在HTML中。
這是有道理的,你不希望將一個數字視為幾個單詞。
簡而言之,你的測試揭示了一個有缺陷的假設 - 太棒了! 但是,就單元測試而言,您的測試存在問題; 在轉換為字符串和從字符串轉換時,應始終包含CultureInfo對象 - 否則,單元測試可能會失敗,具體取決於登錄用戶的區域性設置。 您期望一種特定形式的字符串格式 - 確保明確說明您期望的CultureInfo。
也許您可以在Assert.Equal
方法中更改測試字符串以使用CultureInfo.CurrentCulture.NumberFormat.NumberGroupSeparator
而不是單個空格字符?
160是一個非破壞性的空間,這是有道理的,因為你不希望你的數字在行之間分開。 但是194 ......哦,是的。 UTF8雙倍字節。
首先,.NET中的所有字符串都是Unicode,因此獲取UTF8字節是沒用的。 其次,在比較字符串時,您應該指定文化信息,在使用string.format時,您應該使用IFormatProvider。 這樣您可以控制這些函數中使用的字符。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.