2014/03/22

【C#】いろんなパディング(空白埋めやゼロ埋め)

固定長IFファイルの作成では必要不可欠な処理、パディング。
文字長を一定にしたり、ブラの隙間に夢を詰めたりいろんな使い方がされる。

このエントリでは以下の3種類の方法を紹介する。
  • 基本的なパディング(String.Format)
  • 指定の文字でパディング(PadLeft、PadRight)
  • マルチバイト文字が含まれるパディング(応用編)


基本的なパディング



空白埋め


まずは文字列を指定の桁になるまで空白(スペース)で埋める方法
string value = "test";

// "______test"
String.Format("{0, 10}", value);

// "test______"
String.Format("{0, -10}", value);

{0}はString.Formatでよく使われるインデックス番号。
カンマ以降の数字で桁数を決める。プラスなら右寄せ、マイナスなら左寄せと言った感じ



ゼロ埋め


次に数値を指定の桁になるまでゼロで埋める方法
int value = 123;

// "0000000123"
String.Format("{0:D10}", value);

// "0000000123"
String.Format("{0:0000000000}", value);

// "____000123"
String.Format("{0, 10:D6}", value);

文字列のときとはちょっと変わって、{0:D桁数}もしくは{0:桁数分の0}のように指定する。
最終行は{0, 全体桁数:ゼロ埋め桁数}となる。

ちなみにvalueに文字列を入れるとゼロ埋めされないので注意!

また数値型でもdecimalやdoubleはFormatExceptionになるので要注意!



じゃぁ、decimalやdouble型でゼロ埋めしたり、他の文字で埋めるにはどうすりゃいいのさ?




指定の文字でパディング



String.Formatではパディングできないdecimalやdouble。
空白やゼロ以外でパディングする場合。

などは、以下のような方法で対応可能。

decimal value = 123M;

// "0000000123"
value.ToString().PadLeft(10, '0');

// "1230000000"
value.ToString().PadRight(10, '0');

// "xxxxxxx123"
value.ToString().padLeft(10, 'x');
こんな感じでPadLeft()PadRight()を使うことで解決できる。
Oracleとか使ってる人にはこっちのほうが馴染み深いかも(LPADやRPADみたいな)

文字はchar型のため、シングルクォーテーションで括る必要がある。
ちなみに第2引数の文字を省略すると空白で埋められる




マルチバイト文字が含まれるパディング



実は上記で説明してきたパディングはマルチバイト文字(日本語とか)を入力するといろいろとおかしくなる。

例えば、"あいう".PadLeft(10)とすると"△△△△△△△あいう”となってしまう。
※△は半角スペース

バイトではなく桁数で埋められているため、こんなんで固定長IFファイルなんて作ったら……。


じゃぁ、どうするのか?


「埋めるバイト数」から「文字列のバイト数」と「文字列の長さ」を引いて分だけ埋めれば良い。

// 文字列.PadRight(桁数 - (文字列のバイト数 - 文字列の長さ));
value.PadRight(10 - (Encoding.GetEncoding("Shift_JIS").GetByteCount(value) - value.Length));

仕事で使った具体的な実装例は以下の通り。
// 項目属性の列挙体
enum PadType
{
    Char
    ,Number
}

// パディング処理
public string PaddingInBytes(string value, PadType type, int byteCount)
{
    Encoding enc = Encoding.GetEncoding("Shift_JIS");

    if (byteCount < enc.GetByteCount(value))
    {
        // valueが既定のバイト数を超えている場合は、切り落とし
        value = value.SubString(0, byteCount);
    }

    switch (type)
    {
        case PadType.Char:
            // 文字列の場合 左寄せ+空白埋め
            return value.PadRight(byteCount - (enc.GetByteCount(value) - value.Length));
        case PadType.Number:
            // 数値の場合 右寄せ+0埋め
            return value.PadLeft(byteCount, '0');
        default:
            // 上記以外は全部空白
            return value.PadLeft(byteCount);
    }
}


static Main(string[] args)
{
    Console.WriteLine(this.PaddingInBytes("あいう", PadType.Char, 10));
    Console.WriteLine(this.PaddingInBytes("123", PadType.Number, 15));
}

ってな感じ。
あえて列挙体で「Char」なのか「Number」なのか指定しているけど、typeofで型を引数に渡してあげても同様のことができる。




以上

0 件のコメント :

コメントを投稿