N進数文字列への変換のなかではやりたいがちな2種について。
まずはバイト列→16進数文字列。
ちなみに、需要が高いのか以下のようなガイドがある。
16 進文字列と数値型の間で変換する方法 - C# プログラミング ガイド - C# | Microsoft Learn
まずBitConverter.ToString
を使う方法がある。
private static ReadOnlySpan<byte> Bytes => "Hello, World"u8; private byte[] array = Bytes.ToArray(); public string ByBitConverter() => BitConverter.ToString(array); // 48-65-6C-6C-6F-2C-20-57-6F-72-6C-64
この方法ではセパレーターがハイフン固定で、上述ガイドでは不要ならReplace("-", "")
してくださいとなっている。
また、Span
は受け付けてくれない。
Convert.ToHexString
を使う方法もある。
public string ByConvertToHexString() => Convert.ToHexString(Bytes); // 48656C6C6F2C20576F726C64
比較的新しいAPIだからかSpan
を受け付けてくれ、しかも内部でSIMD分岐をかける最適化が図られているよう。
ただ、出力はセパレーター無し固定。
Method | Mean | Error | StdDev | Gen0 | Allocated | -------------------------- |---------:|----------:|---------:|-------:|----------:| ByBitConverter | 52.69 ns | 33.496 ns | 1.836 ns | 0.0306 | 96 B | ByConvertToHexString | 27.33 ns | 7.049 ns | 0.386 ns | 0.0229 | 72 B |
単純に16進数文字列を得る場合はConvert.ToHexString
で、セパレーターが入っていてほしくてSpan
を渡す必要がなければBitConverter
、となりそう。
以下の折りたたみは参考。勉強として書いた、BitConverter
を見本にSpan
と任意のセパレーターを渡せる感じにしたもの。
折りたたみ
public string ByBitConverterPort() { Span<char> buf = stackalloc char[Bytes.Length * 3 - 1]; ToHexString(Bytes, buf); return new(buf); // 48 65 6C 6C 6F 2C 20 57 6F 72 6C 64 } private static void ToHexString(scoped ReadOnlySpan<byte> bytes, scoped Span<char> buf, char separator = ' ') { int i = 0; int j = 0; byte b = bytes[i++]; buf[j++] = ToCharUpper(b >> 4); buf[j++] = ToCharUpper(b); while (i < bytes.Length) { b = bytes[i++]; buf[j++] = separator; buf[j++] = ToCharUpper(b >> 4); buf[j++] = ToCharUpper(b); } } [MethodImpl(MethodImplOptions.AggressiveInlining)] private static char ToCharUpper(int value) { value &= 0xF; value += '0'; if (value > '9') { value += ('A' - ('9' + 1)); } return (char)value; }
Method | Mean | Error | StdDev | Gen0 | Allocated | -------------------------- |---------:|----------:|---------:|-------:|----------:| ByBitConverterPort | 58.76 ns | 39.613 ns | 2.171 ns | 0.0305 | 96 B |
次にint
→2進数文字列。ここでは、桁数固定(0埋め)を考える。
なお、2進数用の書式指定子は現状存在しない。
【追記】
.NET 8 で二進数指定子が追加された。
標準の数値書式指定文字列 - .NET | Microsoft Learn
これには、Convert.ToString
を用いる。
// int bits; public string ByConvertToString() => Convert.ToString(bits, 2).PadLeft(32, '0');
こちらは、16進数でのConvert.ToHexString
のような相対的に新しいAPIはない。
ただ、汎用化を図らなくていいのであればString.Create
で直接0と1を書くというのも敷居は低い。
public string ByStringCreate() => string.Create(32, bits, static (buf, bits) => { const uint MASK = ((uint)int.MaxValue) + 1; for (int i = 0; i < buf.Length; i++) { buf[i] = (bits & MASK) != 0 ? '1' : '0'; bits <<= 1; } });
Method | Mean | Error | StdDev | Gen0 | Allocated | ------------------ |----------:|----------:|---------:|-------:|----------:| ByConvertToString | 264.90 ns | 3.777 ns | 0.207 ns | 0.0558 | 176 B | ByStringCreate | 58.61 ns | 38.253 ns | 2.097 ns | 0.0280 | 88 B |
16進数の方と違ってこちらは自前でかなり速くなるので並べたけれど、String.Create
に魅入られてわざわざ書こうとしない限り、既に存在し危険も入り込まないConvert.ToString
でよい、という身も蓋もない結論で〆。