NDW

アプリ開発やトラブルシューティング等のノウハウ、キャンプや登山の紹介や体験談など。

.NET Core 1. システムエンジニアリング 実装技術 設計技術

パック10進数の変換方法とC#のサンプル

投稿日:2021年7月4日 更新日:

なお、ゾーン10進数はこちらで紹介しています。

パック10進数

  • ゾーン10進数の変換方法
    • 10進数の各桁を「上位4ビットで1桁、下位4ビットで1桁」のバイトに変換して生成します。
    • 生成したバイト列の最後の下位4ビットが符号部になっており、符号を示す値を設定します。
      符号部の値は実行環境に依存する場合があります。IBM汎用機の場合、符号無しはF(1111)、正はC(1100)、負はD(1101)となります。
  • 各文字コードにおける変換例を次に示します。
    サンプル(整数) パック10進数(16進数)
    123 12 3C
    -123 12 3D
    1234 01 23 4C

C#によるサンプル

  • .NET Core 3.1(C# 8.0)を使ったサンプルとなります。
  • 実現方式として、算術演算・ビット演算を使用して数値ベースで変換を行う方式と、文字列操作で変換を行う方式が考えられます。ここでは、単純で分かりやすい、後者の「文字列操作で変換を行う方式」を使っています。
  • 完全なソースコードはこちらで公開しています。

整数をパック10進数に変換

long型からパック10進数(バイト列)を生成するサンプルです。
整数を2桁毎に分割して16進数文字列を作成し、バイト列を生成しています。
符号があるlong型の使用を想定しているので、符号無しF(1111)は使用していません。

/// <summary>
/// パック10進数: 符号部 正(ASCIIコード使用時)
/// </summary>
private const char PackedDecSignPartPlus = 'C'; // 0b_1100

/// <summary>
/// パック10進数: 符号部 負(ASCIIコード使用時)
/// </summary>
private const char PackedDecSignPartMinus = 'D'; // 0b_1101

/// <summary>
/// 整数からパック10進数を生成する。
/// </summary>
/// <param name="num">整数</param>
/// <returns>パック10進数</returns>
public static byte[] CreatePackedDecimalBytes(long num)
{
    var isPositive = num >= 0;
    var sb = new StringBuilder(num.ToString().TrimStart('-')); // -123 => 123

    // 偶数桁の16進数文字列になるよう0を追加
    // (後で符号部1桁を追加するので、ここでは奇数である必要がある。)
    if (sb.Length % 2 == 0) sb.Insert(0, '0');

    // 符号部1桁を追加(16進数)
    sb.Append(isPositive ? PackedDecSignPartPlus : PackedDecSignPartMinus);

    // 文字列の各2桁を16進数としてバイトに変換する。
    var str = sb.ToString();
    return Enumerable.Range(0, str.Length)
        .Where(i => i % 2 == 0)
        .Select(i => Convert.ToByte(str.Substring(i, 2), 16))
        .ToArray();
}

パック10進数を整数に変換

パック10進数(バイト列)からlong型の整数を生成するサンプルです。
バイト列から16進数文字列を生成し、符号部を除いてそのまま10進数文字列としてlong型に変換します。
16進数文字列が数値以外(A-F)や、符号部が想定している値以外の場合は例外をスローしています。
整数文字列をlong型に変換する際、桁あふれする場合がありますので、業務要件に応じて適切に処理してください。

/// <summary>
/// パック10進数: 符号部 正(ASCIIコード使用時)
/// </summary>
private const char PackedDecSignPartPlus = 'C'; // 0b_1100

/// <summary>
/// パック10進数: 符号部 負(ASCIIコード使用時)
/// </summary>
private const char PackedDecSignPartMinus = 'D'; // 0b_1101

/// <summary>
/// パック10進数から整数を生成する。
/// </summary>
/// <param name="bytes">パック10進数</param>
/// <returns>整数</returns>
public static long ParsePackedDecimal(byte[] bytes)
{
    // 16進数文字列を生成
    var hexes = BitConverter.ToString(bytes).Replace("-", ""); // 1F-34 => 1F34

    // 数値以外(a-f)が含まれないことを検証
    var numstr = hexes[0..^1];
    foreach (var c in numstr)
        if (c < '0' || '9' < c) throw new ArgumentException($"不正な数値部: {hexes}");

    // 符号部が想定される符号値であることを検証
    var signstr = hexes[^1];
    if (signstr == PackedDecSignPartMinus)
        numstr = "-" + numstr;
    else if (signstr != PackedDecSignPartPlus)
        throw new ArgumentException($"不正な符号部: {hexes}");

    return long.Parse(numstr); // OverflowExceptionの場合あり
}







-.NET Core, 1. システムエンジニアリング, 実装技術, 設計技術

関連記事

Excelで大量データから重複値を検索する方法

100万件程の大量データの中で重複するデータを見つける方法を紹介します。 前提条件 検証で使用した環境は次の通りです。 RAND()関数で作成した約100万件(Excelの最大行数となる1,048,5 …

AzureAD B2Cユーザアカウントの操作方法(PowerShell)

Microsoft Graph APIを使ってAzureAD B2Cユーザアカウントを操作するようなアプリケーションを開発しています。 テストエビデンスの取得のために、Microsoft Graph …

.NET Core(C#): enumで文字列を保持

はじめに サンプルは.NET Core 3.1 + C# 8.0で動作確認しています。 列挙体Enumの基本的な使い方はリファレンスやこちらのサンプルをご覧ください。 完全なソースコードはこちらで公開 …

C#: サロゲートペアを考慮したUnicodeコードポイント変換

C#の文字列はUTF-16を使用しているので、UnicodeとUTF-16を中心とした話になります。 要約 Unicodeに関する前提知識 Unicodeでは各国で使用する文字一覧を定義(符号化文字集 …

wildflyへのwarデプロイの自動化

更新したWebアプリをWildflyにデプロイするのが面倒なのでスクリプトを作成してみました。 前提 実行環境はCentOS Linux 7です。 JavaEEのWebアプリの配布形式であるwarファ …