2


0

string.Formatによって返される文字列は、奇妙なエンコーディングを使用しているようです。 フォーマット文字列に含まれるスペースは、ソースコードで宣言された文字列に含まれるスペースとは異なるバイト値を使用して表されます。

次のテストケースは問題を示しています。

[Test]
public void FormatSize_Regression(){文字列size1023 = FileHelper.FormatSize(1023); Assert.AreEqual( "1 023 Bytes"、size1023); }

失敗する

文字列の長さは両方とも11です。 文字列はインデックス1で異なります。 予期される値: "1 023バイト"しかし、次のとおりでした: "1 023バイト" ------------ ^

FormatSizeメソッド:

public static string FormatSize(long size){if(size <1024)が文字列を返します。Format( "{0:N0} Bytes"、size);そうでなければ(size <1024 * 1024)がstring.Format( "{0:N2} KB"、(double)((double)size / 1024));を返します。それ以外の場合は、string.Format( "{0:N2} MB"、(double)((double)size /(1024 * 1024)));を返します。 }

Assert行にブレークポイントが設定されている場合のVSイミディエイトウィンドウから:

size1023 "1 023バイト"

System.Text.Encoding.UTF8.GetBytes(size1023){byte [12]} [0]:49 [1]:194 <---------スペースは194/160です。 Unicodeバイトは、スペースを160にする必要があることを示します。 当時の194は何ですか? [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 <---------スペースはここで32です[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ここ[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

質問:これはどのように可能ですか?

6 Answer


12


あなたの現在の文化は興味深い「千」区切り文字 - U 00A0を使用しているのではないかと思います。 それは正直に言うと、まったく不合理な千の区切り文字ではありません…​ このようなテキストは表示されないはずです。

ファイルのサイズは1 023バイトです。

代わりにあなたが得るでしょう

ファイルのサイズは1 023バイトです。

私の箱には、代わりに "1,023"が入っています。 あなたの `FormatSize`メソッドに現在のカルチャ、または特定のカルチャを使用させたいですか? もしそれが現在の文化であれば、おそらくあなたのユニットテストに文化を指定させるべきです。 これに使用するラッパーメソッドがいくつかあります。

内部静的void WithInvariantCulture(アクションアクション){WithCulture(CultureInfo.InvariantCulture、アクション); }

内部静的void WithCulture(CultureInfo culture、アクションアクション){CultureInfo original = Thread.CurrentThread.CurrentCulture; {Thread.CurrentThread.CurrentCulture = culture;を試してください。アクション(); {Thread.CurrentThread.CurrentCulture = original;} }}

だから私は実行することができます:

WithInvariantCulture(()=> {//テスト本体};

正確な文字列をテストしたい場合は、次のようにします。

Assert.AreEqual( "1 \ u00A0023バイト"、size1023);


4


UTF8のUnicode 160は、シングルバイト160では表されませんが、2バイトで表されます。 そして確認せずに、私は194 160であることを賭けたいと思います。

実際、127を超えるUnicodeコードポイントは、複数のバイトで表されます。

そして、あなたのCultureInfoは、1000単位の区切り文字として、改行なしのスペース(160)を使用しています。自分で入力したような単純なスペース(32)は使用していません。


2


194、160はコードポイント160のutf8です。改行のないスペース - htmlでは ``です。

それは理にかなっている、あなたは一つの数字が複数の単語と見なされることを望まない。

要するに、あなたのテストは欠陥のある仮定を明らかにしました - 素晴らしい! ただし、単体テストに関しては、テストには問題があります。文字列との変換時には必ずCultureInfoオブジェクトを含める必要があります。そうしないと、ログインユーザーのカルチャ設定によっては単体テストが失敗する可能性があります。 あなたは文字列フォーマットの特定の形式を期待しています - あなたが明示的にあなたが期待しているCultureInfoを明示することを確かめてください。


2


たぶんあなたは単一のスペース文字の代わりに CultureInfo.CurrentCulture.NumberFormat.NumberGroupSeparator`を使うために Assert.Equal`メソッドのテスト文字列を変更できますか?


1


160は壊れないスペースです。これは理にかなっているので、番号を行に分割したくない場合があります。 しかし194 …​ そうそう。 UTF8ダブルバイト


0


まず第一に、.NETのすべての文字列はUnicodeなので、UTF8バイトを取得するのは無駄です。 第二に、文字列を比較するときはカルチャ情報を指定し、string.formatを使用するときはIFormatProviderを使用する必要があります。 これにより、これらの関数で使用される文字を制御できます。