C# - 16進数文字列とバイト列の変換について

C#における16進数文字列(string)とバイト(byte)の相互変換について知っておく。

ソースコード

byte から string へは BitConverter.ToString(byteData)で変換できる。
でも逆の変換はライブラリにないので、自分で書く必要がある。
大体以下のような感じになると思う。

using System;
using System.Globalization;

public static byte[] HexStringToBytes(string s)
{
    if (s == null)
    {
        throw new ArgumentNullException();
    }
    // 入力文字列の長さは偶数であること
    if (s.Length % 2 != 0)
    {
        throw new FormatException();
    }

    // 長さ0は空を返す
    if (s.Length == 0)
    {
        return Array.Empty<byte>();
    }

    // 半分の長さのバイト列ができる
    var bytes = new byte[s.Length / 2];
    for (int i = 0; i < bytes.Length; i++)
    {
        bytes[i] = byte.Parse(s.AsSpan().Slice(i*2, 2), NumberStyles.AllowHexSpecifier);
    }
    
    return bytes;
}

簡単に解説

まず入力チェックで、NULLはダメ。
長さについて、1バイトは二つの16進数文字で構成されるので、バイト配列に変換しようとしている文字列の長さは偶数のはず。
ということで奇数長はフォーマット誤りとする。
例外にメッセージ付けた方が良いかもしれない。

長さ0は何もせずに空配列を返す。
new byte[0]でも良いのかもしれないが、わざわざ用意されたっぽいのでArray.Empty<>を使っておく。

変換処理について、
入力文字列の半分の長さのバイト配列ができるので、必要な配列を用意して値を格納していく。
それぞれの型にはParse()メソッドが用意されているので、それ(byte.Parse())を使って変換する。
Parseデータとして、Substring()ではなくSpan<>(ReadOnlySpan<>)で部分文字列を渡す。
Span<>は今のstringの内容をそのまま参照(Substring()は新たなstringを生成)するので早いのだそう。
2番目の引数はドキュメント見たら丁度よいのがあったので、そのままコピペ。
(onvert.ToBytes(string, 16)というやり方もあった。そっちのほうが普通なのかもしれない)

以上。


See also