雑記 - otherwise

最近はDQ10しかやっていないダメ技術者がちまちまと綴る雑記帳

16 進数文字列の処理

ここのところお仕事過多な事もあって blog がちっとも更新出来ていません。。。
WebService から情報を取得するアプリケーションの作成」の 3 回目は手元で一生懸命原稿を書いているところです。今しばらくお待ちくださいませ><
で、あまりにも忙しいと何となく他の事をやりたくなるのが常でありまして。 ^^;
ちょっとした小ネタを。

上記記事では char から int への変換を計算で行っていますが、折角組み込みで Parse メソッドがあるのでそちらを使ってやる方法をご紹介します。
ついでにビット演算については BitArray (System.Collections) を利用して Bit 構造体なるものを作ってみました。 ^^;

Bit 構造体

# Equals とか GetHashCode とかの実装は面倒なので省略しています。
# まぁ、 GetHashCode については、実質 IntValue と同等な値なので、 "return IntValue.GetHashCode()" とかで良い気がします。 :p
# 演算についてはオーバーフローとか一切気にしてないので、このまま実運用とかで使うのは危険。。。

using System;
using System.Collections;
using System.Globalization;
using System.Linq;
using System.Text;

public struct Bit
{
  private BitArray _bitArray;

  #region int 値
  public int IntValue { get; set; }
  #endregion

  #region インデクサ
  public bool this[int index]
  {
    get { return _bitArray[index]; }
    set
    {
      _bitArray[index] = value;
      RefreshIntValue();
    }
  }
  #endregion

  #region コンストラクタ
  public Bit(string hexString)
    : this()
  {
    var intValue = Bit.HexStringToInt32(hexString);
    _bitArray = new BitArray(new[] { intValue });
    IntValue = intValue;
  }

  public Bit(int intValue)
    : this()
  {
    _bitArray = new BitArray(new[] { intValue });
    IntValue = intValue;
  }
  #endregion

  #region static メソッド
  public static int HexStringToInt32(string hexString)
  {
    return Int32.Parse(hexString, NumberStyles.HexNumber);
  }

  public static string Int32ToHexString(int intValue)
  {
    return intValue.ToString("X");
  }
  #endregion

  #region 文字列化
  public string ToHexString()
  {
    return Bit.Int32ToHexString(IntValue);
  }

  public string ToBitString()
  {
    return _bitArray.Cast<bool>()
                    .Reverse()
                    .SkipWhile(b => !b)
                    .Aggregate(
                      new StringBuilder(),
                      (builder, b) => builder.Append(b ? 1 : 0)
                    )
                    .ToString();
  }
  #endregion

  #region int 値最新化
  private void RefreshIntValue()
  {
    var round = 1;
    IntValue = 0;
    foreach (bool bit in _bitArray)
    {
      if (bit)
      {
        IntValue += round;
      }
      round *= 2;
    }
  }
  #endregion

  #region int との相互変換
  public static implicit operator Bit(int intValue)
  {
    return new Bit(intValue);
  }

  public static implicit operator Int32(Bit bitValue)
  {
    return bitValue.IntValue;
  }
  #endregion

  #region string との相互変換
  public static explicit operator Bit(string hexString)
  {
    return new Bit(hexString);
  }

  public static implicit operator String(Bit bitValue)
  {
    return bitValue.ToHexString();
  }
  #endregion

  #region 演算子オーバーロード
  public static Bit operator +(Bit value, Bit other)
  {
    return new Bit(value.IntValue + other.IntValue);
  }

  public static Bit operator -(Bit value, Bit other)
  {
    return new Bit(value.IntValue - other.IntValue);
  }

  public static Bit operator *(Bit value, Bit other)
  {
    return new Bit(value.IntValue * other.IntValue);
  }

  public static Bit operator /(Bit value, Bit other)
  {
    return new Bit(value.IntValue / other.IntValue);
  }

  public static Bit operator %(Bit value, Bit other)
  {
    return new Bit(value.IntValue % other.IntValue);
  }

  public static bool operator ==(Bit value, Bit other)
  {
    return value.IntValue == other.IntValue;
  }

  public static bool operator !=(Bit value, Bit other)
  {
    return value.IntValue != other.IntValue;
  }
  #endregion
}

使い方

// 16 進数文字列 → int
var sampleString = "AF7";
var sampleInteger = Bit.HexStringToInt32(sampleString);
Console.WriteLine("{0} -> {1}", sampleString, sampleInteger);
Console.WriteLine();

// int → 16 進数文字列
var sample2Integer = 299;
var sample2String = Bit.Int32ToHexString(sample2Integer);
Console.WriteLine("{0} -> {1}", sample2Integer, sample2String);
Console.WriteLine();

// Bit 構造体の利用

// 16 進数文字列 → Bit 構造体
var sample3String = "3B9";
var sample3Bit = (Bit)sample3String; // 明示的な型変換が可能

// int / 16 進数文字列 / 2 進数文字列として取得
var sample3Integer = sample3Bit.IntValue;
var sample3HexString = sample3Bit.ToHexString();
var sample3BitString = sample3Bit.ToBitString();
Console.WriteLine("[int] {0}", sample3Integer);
Console.WriteLine("[16] {0}", sample3HexString);
Console.WriteLine("[2] {0}", sample3BitString);
Console.WriteLine();

// int → Bit 構造体
Bit sample4Bit = 189; // 暗黙的な型変換が可能
int sample4Integer = sample4Bit; // Bit 構造体 → int も暗黙的な型変換が可能
Console.WriteLine("[Bit] {0}", sample4Bit.ToHexString());
Console.WriteLine("[int] {0}", sample4Integer);
Console.WriteLine();

// 特定箇所のビットを bool 値で取得
Bit sample5Bit = 288;
var sample5ChoiceIndex = 4;
var sample5ChoiceBit = sample5Bit[sample5ChoiceIndex]; // インデックスアクセスが可能
Console.WriteLine("{0} [{1}] -> {2}", sample5Bit.ToHexString(), sample5ChoiceIndex, sample5ChoiceBit);
Console.WriteLine("<{0}>", sample5Bit.ToBitString());
Console.WriteLine();

// 特定箇所のビットを更新
var sample6Bit = (Bit)"BDF37";
var sample6OriginalHexString = sample6Bit.ToHexString();
var sample6OriginalBitString = sample6Bit.ToBitString();
var sample6OriginalInteger = sample6Bit.IntValue;
var updateIndex = 3;
var updateValue = true;
sample6Bit[updateIndex] = updateValue; // インデックスアクセスが可能
Console.WriteLine("{0} >> [{1}, {2}] -> {3}", sample6OriginalHexString, updateIndex, updateValue, sample6Bit.ToHexString());
Console.WriteLine("{0} >> [{1}, {2}] -> {3}", sample6OriginalInteger, updateIndex, updateValue, sample6Bit.IntValue);
Console.WriteLine("before: <{0}>", sample6OriginalBitString);
Console.WriteLine("after : <{0}>", sample6Bit.ToBitString());
Console.WriteLine();

// 演算
Bit sample7Bit = 27;
Bit sample8Bit = (Bit)"C";
var plus = sample7Bit + sample8Bit;
var minus = sample7Bit - sample8Bit;
var times = sample7Bit * sample8Bit;
var divide = sample7Bit / sample8Bit;
var mod = sample7Bit % sample8Bit;
Console.WriteLine("Hex: {0}, {1}", sample7Bit.ToHexString(), sample8Bit.ToHexString());
Console.WriteLine("Int: {0}, {1}", sample7Bit.IntValue, sample8Bit.IntValue);
Console.WriteLine("+ >> Hex: {0} , Int: {1}", plus.ToHexString(), plus.IntValue);
Console.WriteLine("- >> Hex: {0} , Int: {1}", minus.ToHexString(), minus.IntValue);
Console.WriteLine("* >> Hex: {0} , Int: {1}", times.ToHexString(), times.IntValue);
Console.WriteLine("/ >> Hex: {0} , Int: {1}", divide.ToHexString(), divide.IntValue);
Console.WriteLine("% >> Hex: {0} , Int: {1}", mod.ToHexString(), mod.IntValue);
  • 出力結果
AF7 -> 2807

299 -> 12B

[int] 953
[16] 3B9
[2] 1110111001

[Bit] BD
[int] 189

120 [4] -> False
<100100000>

BDF37 >> [3, True] -> BDF3F
778039 >> [3, True] -> 778047
before: <10111101111100110111>
after : <10111101111100111111>

Hex: 1B, C
Int: 27, 12
+ >> Hex: 27 , Int: 39
- >> Hex: F , Int: 15
* >> Hex: 144 , Int: 324
/ >> Hex: 2 , Int: 2
% >> Hex: 3 , Int: 3