タグ : C#

 

.NET 文字列が数値であるかをチェックする

C#、VB.NETで文字列が小数を含む数値に変換できるかをチェックします。今回は正規表現を利用して符号なし数値、符号あり数値をチェックする方法をご紹介します。
 
●文字列が符号なし数値(小数を含む)であるかをチェック
        /// <summary>
        /// 文字列が符号なしの小数かどうかを判定します
        /// </summary>
        /// <param name="target">対象の文字列</param>
        /// <returns>文字列が符号なしの小数の場合はtrue、それ以外はfalse</returns>
        public static bool IsUnsignedDecimal(string target)
        {
            return new Regex("^[0-9]*\\.?[0-9]+$").IsMatch(target);
        }
 
 
●文字列が符号あり数値(小数を含む)であるかをチェック
        /// <summary>
        /// 文字列が符号ありの小数かどうかを判定します
        /// </summary>
        /// <param name="target">対象の文字列</param>
        /// <returns>文字列が符号ありの小数の場合はtrue、それ以外はfalse</returns>
        public static bool IsDecimal(string target)
        {
            return new Regex("^[-+]?[0-9]*\\.?[0-9]+$").IsMatch(target);
        }
 
 
以下のエリアでは「IsUnsignedDecimal」と「IsDecimal」メソッドを実際に動かした時の挙動を確認できます。
 
●文字列が符号なし数値(小数を含む)であるかをチェック
IsUnsignedDecimal(" 
 ");    
実行結果:
 
●文字列が符号あり数値(小数を含む)であるかをチェック
IsDecimal(" 
 ");                 
実行結果:
 

.NET 文字列が整数であるかをチェックする

C#、VB.NETで文字列が整数に変換できるかをチェックする方法は何種類かありますが、ここでは正規表現を利用して符号なし整数、符号あり整数をチェックする方法をご紹介します。
 
●文字列が符号なし整数であるかをチェック
        /// <summary>
        /// 文字列が符号なしの整数かどうかを判定します
        /// </summary>
        /// <param name="target">対象の文字列</param>
        /// <returns>文字列が符号なしの整数の場合はtrue、それ以外はfalse</returns>
        public bool IsUnsignedIntegers(string target)
        {
            return new Regex("^[0-9]+$").IsMatch(target);
        }
 
 
●文字列が符号あり整数であるかをチェック
        /// <summary>
        /// 文字列が符号ありの整数かどうかを判定します
        /// </summary>
        /// <param name="target">対象の文字列</param>
        /// <returns>文字列が符号ありの整数の場合はtrue、それ以外はfalse</returns>
        public bool IsIntegers(string target)
        {
            return new Regex("^[-+]?[0-9]+$").IsMatch(target);
        }
 
 
以下のエリアでは「IsUnsignedIntegers」と「IsIntegers」メソッドを実際に動かした時の挙動を確認できます。
 
●文字列が符号なし整数であるかをチェック
IsUnsignedIntegers(" 
 ");    
実行結果:
 
●文字列が符号あり整数であるかをチェック
IsIntegers(" 
 ");                 
実行結果:
 

.NET 全てのオブジェクトをコピーする汎用ディープコピーメソッド

前回投稿した「浅いコピーと深いコピー」では、データクラスにディープコピーメソッドを実装しましたが、全てのデータクラスに深いコピーが必要なわけではありません。
 
汎用のディープコピーメソッドを作成しておくと、必要に応じてオブジェクトをコピーできるので便利です。
 
ディープコピーメソッドのソースコードは以下になります。
 
using System;
using System.IO;
using System.Runtime.Serialization.Formatters.Binary;

namespace ShallowCopyTest
{
    /// <summary>
    /// コピーユーティリティ
    /// </summary>
    public static class CopyUtility
    {
        /// <summary>
        /// 指定されたインスタンスの深いコピーを生成し返します
        /// </summary>
        /// <typeparam name="T">コピーするインスタンスの型</typeparam>
        /// <param name="original">コピー元のインスタンス</param>
        /// <returns>指定されたインスタンスの深いコピー</returns>
        public static T DeepCopy<T>(T original)
        {
            // シリアル化した内容を保持するメモリーストリームを生成
            MemoryStream stream = new MemoryStream();

            try
            {
                // バイナリ形式でシリアライズするためのフォーマッターを生成
                BinaryFormatter formatter = new BinaryFormatter();

                // コピー元のインスタンスをシリアライズ
                formatter.Serialize(stream, original);

                // メモリーストリームの現在位置を先頭に設定
                stream.Position = 0L;

                // メモリーストリームの内容を逆シリアル化
                return (T)formatter.Deserialize(stream);
            }
            finally
            {
                stream.Close();
            }
        }
    }
}
 
 
それでは前回の会員クラス(Membership)をディープコピーしてみましょう。
 
    // 会員1を生成
    Membership membership1 = new Membership();

    // 会員1のIDとパスワード、ニックネームを設定
    membership1.ID = 1;
    membership1.Password = "1234567890";
    membership1.Nickname = "変数名.com";

    // 会員2に会員1のディープコピーを代入
    Membership membership2 =
        CopyUtility.DeepCopy<Membership>(membership1);

    // 会員1の情報を表示
    Console.WriteLine("会員1 [{0}][{1}][{2}]",
        membership1.ID, membership1.Password, membership1.Nickname);

    // 会員2の情報を表示
    Console.WriteLine("会員2 [{0}][{1}][{2}]",
        membership2.ID, membership2.Password, membership2.Nickname);

    Console.WriteLine();

    // 会員1の情報を変更
    membership1.ID = 999;
    membership1.Password = "ABCDEFGHIJ";
    membership1.Nickname = "リファクタ";

    // 会員1の情報を表示
    Console.WriteLine("会員1 [{0}][{1}][{2}]",
        membership1.ID, membership1.Password, membership1.Nickname);

    // 会員2の情報を表示
    Console.WriteLine("会員2 [{0}][{1}][{2}]",
        membership2.ID, membership2.Password, membership2.Nickname);
実行結果:
 
会員1 [1][1234567890][変数名.com]
会員2 [1][1234567890][変数名.com]
 
会員1 [999][ABCDEFGHIJ][リファクタ]
会員2 [1][1234567890][変数名.com]
 
無事に会員1の情報だけが変更されました。
 

浅いコピーと深いコピー

オブジェクトをコピーしてデータを編集する。たとえば「保存」ボタンをクリックしたときに、編集データの保存かキャンセルを選べるような場合に有効ですが、使い方を誤ると思わぬ事故を誘発します。
 
事故の多くは浅いコピー(シャローコピー/Shallow Copy)と深いコピー(ディープコピー/Deep Copy)を間違えて「本来変わってはいけない値が変わってしまう」というものです。
 
そこで本稿ではオブジェクトの複製についてまとめていきたいと思います。
 
はじめに「会員」の情報が以下のように定義されていたとします。
 
●会員情報のクラス図
会員情報
●アカウントクラス(Account)のソース
using System;

namespace ShallowCopyTest
{
    /// <summary>
    /// アカウント
    /// </summary>
    public class Account
    {
        /// <summary>
        /// ID
        /// </summary>
        public int ID;

        /// <summary>
        /// パスワード
        /// </summary>
        public string Password;

        /// <summary>
        /// コンストラクタ
        /// </summary>
        public Account()
        {
        }
    }
}
 
●会員クラス(Membership)のソース
using System;

namespace ShallowCopyTest
{
    /// <summary>
    /// 会員
    /// </summary>
    public class Membership
    {
        /// <summary>
        /// アカウント
        /// </summary>
        private Account _account = new Account();

        /// <summary>
        /// ID
        /// </summary>
        public int ID
        {
            get { return this._account.ID; }
            set { this._account.ID = value; }
        }

        /// <summary>
        /// パスワード
        /// </summary>
        public string Password
        {
            get { return this._account.Password; }
            set { this._account.Password = value; }
        }

        /// <summary>
        /// ニックネーム
        /// </summary>
        public string Nickname;

        /// <summary>
        /// コンストラクタ
        /// </summary>
        public Membership()
        {
        }

        /// <summary>
        /// 現在のインスタンスのコピーを作成します
        /// </summary>
        /// <returns>現在のインスタンスのコピー</returns>
        public Membership Clone()
        {
            return (Membership)MemberwiseClone();
        }
    }
}
 
オブジェクトのコピーで一番簡単な方法は「代入」です。ためしに以下のコードを実行してみましょう。
 
        // 会員1を生成
        Membership membership1 = new Membership();

        // 会員1のIDとパスワード、ニックネームを設定
        membership1.ID = 1;
        membership1.Password = "1234567890";
        membership1.Nickname = "変数名.com";

        // 会員2に会員1を代入
        Membership membership2 = membership1;

        // 会員1の情報を表示
        Console.WriteLine("会員1 [{0}][{1}][{2}]",
            membership1.ID, membership1.Password, membership1.Nickname);

        // 会員2の情報を表示
        Console.WriteLine("会員2 [{0}][{1}][{2}]",
            membership2.ID, membership2.Password, membership2.Nickname);

        Console.WriteLine();

        // 会員1の情報を変更
        membership1.ID = 999;
        membership1.Password = "ABCDEFGHIJ";
        membership1.Nickname = "リファクタ";

        // 会員1の情報を表示
        Console.WriteLine("会員1 [{0}][{1}][{2}]",
            membership1.ID, membership1.Password, membership1.Nickname);

        // 会員2の情報を表示
        Console.WriteLine("会員2 [{0}][{1}][{2}]",
            membership2.ID, membership2.Password, membership2.Nickname);
実行結果:
 
会員1 [1][1234567890][変数名.com]
会員2 [1][1234567890][変数名.com]
 
会員1 [999][ABCDEFGHIJ][リファクタ]
会員2 [999][ABCDEFGHIJ][リファクタ]
 
会員1の情報だけを変えたつもりが、会員2の情報まで変わってしまいました。これは「membership1」と「membership2」の参照先が同じなので、会員1への変更が会員2にも反映されてしまったことが原因です。
 
会員1への変更が会員2にも反映されてしまった。。

会員1への変更が会員2にも反映されてしまった。。

 
それでは会員クラス(Membership)に実装した「Clone」メソッドでコピーしてみましょう。
 
        // 会員1を生成
        Membership membership1 = new Membership();

        // 会員1のIDとパスワード、ニックネームを設定
        membership1.ID = 1;
        membership1.Password = "1234567890";
        membership1.Nickname = "変数名.com";

        // 会員2に会員1のシャローコピーを代入
        Membership membership2 = membership1.Clone();

        // 会員1の情報を表示
        Console.WriteLine("会員1 [{0}][{1}][{2}]",
            membership1.ID, membership1.Password, membership1.Nickname);

        // 会員2の情報を表示
        Console.WriteLine("会員2 [{0}][{1}][{2}]",
            membership2.ID, membership2.Password, membership2.Nickname);

        Console.WriteLine();

        // 会員1の情報を変更
        membership1.ID = 999;
        membership1.Password = "ABCDEFGHIJ";
        membership1.Nickname = "リファクタ";

        // 会員1の情報を表示
        Console.WriteLine("会員1 [{0}][{1}][{2}]",
            membership1.ID, membership1.Password, membership1.Nickname);

        // 会員2の情報を表示
        Console.WriteLine("会員2 [{0}][{1}][{2}]",
            membership2.ID, membership2.Password, membership2.Nickname);
実行結果:
 
会員1 [1][1234567890][変数名.com]
会員2 [1][1234567890][変数名.com]
 
会員1 [999][ABCDEFGHIJ][リファクタ]
会員2 [999][ABCDEFGHIJ][変数名.com]
 
ニックネームは会員1だけ変わりましたが、アカウントの情報は会員2も変わってしまいました。これは会員クラス(Membership)に実装した「Clone」メソッドで使用している「MemberwiseClone」メソッドが、浅いコピーを作成することが原因です。
 
浅いコピーは値型のフィールドをビット単位でコピーしますが、参照型のフィールドは参照のみをコピーします。
 
会員1のアカウント情報の変更が会員2にも反映されてしまった。。

会員1のアカウント情報の変更が会員2にも反映されてしまった。。

 
参照型のフィールドもビット単位でコピーするためには、深いコピーを作成する必要があります。
 
深いコピーを作成する方法の一つにシリアライズを利用する方法があり、私はこの方法が一番わかりやすくて気に入っています。
 
シリアライズを利用するためには、クラスに[Serializable]属性を付与する必要があります。アカウントクラス(Account)と会員クラス(Membership)に付与し、続いて「Clone」メソッドをシリアライズを利用して書き換えてみましょう。
 
●アカウントクラス(Account)のソース
using System;

namespace ShallowCopyTest
{
    /// <summary>
    /// アカウント
    /// </summary>
    [Serializable]
    public class Account
    {
        /// <summary>
        /// ID
        /// </summary>
        public int ID;

        /// <summary>
        /// パスワード
        /// </summary>
        public string Password;

        /// <summary>
        /// コンストラクタ
        /// </summary>
        public Account()
        {
        }
    }
}
 
●会員クラス(Membership)のソース
using System;
using System.IO;
using System.Runtime.Serialization.Formatters.Binary;

namespace ShallowCopyTest
{
    /// <summary>
    /// 会員
    /// </summary>
    [Serializable]
    public class Membership
    {
        /// <summary>
        /// アカウント
        /// </summary>
        private Account _account = new Account();

        /// <summary>
        /// ID
        /// </summary>
        public int ID
        {
            get { return this._account.ID; }
            set { this._account.ID = value; }
        }

        /// <summary>
        /// パスワード
        /// </summary>
        public string Password
        {
            get { return this._account.Password; }
            set { this._account.Password = value; }
        }

        /// <summary>
        /// ニックネーム
        /// </summary>
        public string Nickname;

        /// <summary>
        /// コンストラクタ
        /// </summary>
        public Membership()
        {
        }

        /// <summary>
        /// 現在のインスタンスのコピーを作成します
        /// </summary>
        /// <returns>現在のインスタンスのコピー</returns>
        public Membership Clone()
        {
            // シリアル化した内容を保持するメモリーストリームを生成
            MemoryStream stream = new MemoryStream();

            try
            {
                // バイナリ形式でシリアライズするためのフォーマッターを生成
                BinaryFormatter formatter = new BinaryFormatter();

                // 自分自身をシリアライズ
                formatter.Serialize(stream, this);

                // メモリーストリームの現在位置を先頭に設定
                stream.Position = 0L;

                // メモリーストリームの内容を逆シリアル化
                return (Membership)formatter.Deserialize(stream);
            }
            finally
            {
                stream.Close();
            }
        }
    }
}
 
それでは会員クラス(Membership)に実装した「Clone」メソッドでもう一度コピーしてみましょう。
 
        // 会員1を生成
        Membership membership1 = new Membership();

        // 会員1のIDとパスワード、ニックネームを設定
        membership1.ID = 1;
        membership1.Password = "1234567890";
        membership1.Nickname = "変数名.com";

        // 会員2に会員1のディープコピーを代入
        Membership membership2 = membership1.Clone();

        // 会員1の情報を表示
        Console.WriteLine("会員1 [{0}][{1}][{2}]",
            membership1.ID, membership1.Password, membership1.Nickname);

        // 会員2の情報を表示
        Console.WriteLine("会員2 [{0}][{1}][{2}]",
            membership2.ID, membership2.Password, membership2.Nickname);

        Console.WriteLine();

        // 会員1の情報を変更
        membership1.ID = 999;
        membership1.Password = "ABCDEFGHIJ";
        membership1.Nickname = "リファクタ";

        // 会員1の情報を表示
        Console.WriteLine("会員1 [{0}][{1}][{2}]",
            membership1.ID, membership1.Password, membership1.Nickname);

        // 会員2の情報を表示
        Console.WriteLine("会員2 [{0}][{1}][{2}]",
            membership2.ID, membership2.Password, membership2.Nickname);
実行結果:
 
会員1 [1][1234567890][変数名.com]
会員2 [1][1234567890][変数名.com]
 
会員1 [999][ABCDEFGHIJ][リファクタ]
会員2 [1][1234567890][変数名.com]
 
今度は無事に会員1の情報だけが変更されました。
 
会員1の情報のみ変更できた!

会員1の情報だけが変更された!

 
このように深いコピーはいいことずくめのように見えますが、クラスの内容を一旦ストリームに吐き出し、そのストリームから再度クラスを生成しているので、処理は当然遅くなります。
 
何でもかんでも深いコピーを利用するのではなく、参照系は浅いコピー、更新系は深いコピーを利用するなど、ケースバイケースで使い分けることをおススメします。
 

.NET 文字列を指定されたバイト数に成型する

他システムと固定長ファイルで連携したり、帳票レイアウトのための位置調整など、「文字列を指定されたバイト数に成型する(かつ文字化けはさせない)」要件は意外と多いものです。
 
以前に投稿した「TruncateByteLeftメソッド」や「GetByteCountメソッド」などを組み合わせると、比較的簡単に成型することができます。
 
●左詰めで成型する場合
StringUtility utility = new StringUtility();

utility.FormFixedByteLengthLeft("1あいうえお", 4);
実行結果:”1あ¸”
 
●右詰めで成型する場合
StringUtility utility = new StringUtility();

utility.FormFixedByteLengthRight("1あいうえお", 4);
実行結果:”¸1あ”
 
実行結果の半角スペースは「¸」で表します。
上記例では切り詰める方向が左からですが、右から切り詰めるオーバーロードも用意しております。
 
以下のエリアではFormFixedByteLengthLeftメソッドとFormFixedByteLengthRightメソッドを実際に動かした時の挙動を確認できます。
 
StringUtility utility = new StringUtility();

utility.FormFixedByteLengthLeft(
    
 ", 
 );
実行結果:
“”
 
StringUtility utility = new StringUtility();

utility.FormFixedByteLengthRight(
    
 ", 
 );
実行結果:
“”
 
実行結果の半角スペースは「¸」で表します。
 
FormFixedByteLengthLeftメソッド、FormFixedByteLengthRightメソッドのソースコードは以下になります。
 
        /// <summary>
        /// 文字列を指定されたバイト長に左詰めで成型します
        /// </summary>
        /// <param name="target">対象の文字列</param>
        /// <param name="lengthByte">バイト長</param>
        /// <param name="padCharacter">パッドキャラクター</param>
        /// <param name="isTruncateLeft">文字列を左側から切り詰める場合はtrue、それ以外はfalse</param>
        /// <returns>指定されたバイト長に左詰めで成型された文字列</returns>
        /// <remarks>成型された文字列の先頭・末尾に全角文字途中の要素が混入している場合は除去し、パッドキャラクターを追加します</remarks>
        /// <remarks>Unicodeでバイト長に奇数が指定された場合などは、バイト長を超えない最大の長さで成型します</remarks>
        public string FormFixedByteLengthLeft(string target, int lengthByte,
            char padCharacter, bool isTruncateLeft)
        {
            // 部分文字列を取得
            string partialString = isTruncateLeft ? TruncateByteLeft(target, lengthByte) :
                TruncateByteRight(target, lengthByte);

            // パッドするバイト長を取得
            int padLengthByte = lengthByte - GetByteCount(partialString);

            // パッドする必要がない場合
            if (padLengthByte == 0)
            {
                return partialString;
            }

            // パッドする長さを取得
            int padLength = padLengthByte / GetByteCount(padCharacter.ToString());

            return partialString.PadRight(partialString.Length + padLength, padCharacter);
        }

        /// <summary>
        /// 文字列を指定されたバイト長に左詰めで成型します
        /// </summary>
        /// <param name="target">対象の文字列</param>
        /// <param name="lengthByte">バイト長</param>
        /// <param name="padCharacter">パッドキャラクター</param>
        /// <returns>指定されたバイト長に左詰めで成型された文字列</returns>
        /// <remarks>成型された文字列の末尾に全角文字途中の要素が混入している場合は除去し、パッドキャラクターを追加します</remarks>
        /// <remarks>Unicodeでバイト長に奇数が指定された場合などは、バイト長を超えない最大の長さで成型します</remarks>
        public string FormFixedByteLengthLeft(string target, int lengthByte,
            char padCharacter)
        {
            return FormFixedByteLengthLeft(target, lengthByte, padCharacter, true);
        }

        /// <summary>
        /// 文字列を指定されたバイト長に左詰めで成型します
        /// </summary>
        /// <param name="target">対象の文字列</param>
        /// <param name="lengthByte">バイト長</param>
        /// <returns>指定されたバイト長に左詰めで成型された文字列</returns>
        /// <remarks>成型された文字列の末尾に全角文字途中の要素が混入している場合は除去し、半角スペースを追加します</remarks>
        /// <remarks>Unicodeでバイト長に奇数が指定された場合などは、バイト長を超えない最大の長さで成型します</remarks>
        public string FormFixedByteLengthLeft(string target, int lengthByte)
        {
            return FormFixedByteLengthLeft(target, lengthByte, ’ ’);
        }

        /// <summary>
        /// 文字列を指定されたバイト長に右詰めで成型します
        /// </summary>
        /// <param name="target">対象の文字列</param>
        /// <param name="lengthByte">バイト長</param>
        /// <param name="padCharacter">パッドキャラクタ</param>
        /// <param name="isTruncateLeft">文字列を左側から切り詰める場合はtrue、それ以外はfalse</param>
        /// <returns>指定されたバイト長に右詰めで成型された文字列</returns>
        /// <remarks>成型された文字列の先頭・末尾に全角文字途中の要素が混入している場合は除去し、パッドキャラクターを追加します</remarks>
        /// <remarks>Unicodeでバイト長に奇数が指定された場合などは、バイト長を超えない最大の長さで成型します</remarks>
        public string FormFixedByteLengthRight(string target, int lengthByte,
            char padCharacter, bool isTruncateLeft)
        {
            // 部分文字列を取得
            string partialString = isTruncateLeft ? TruncateByteLeft(target, lengthByte) :
                TruncateByteRight(target, lengthByte);

            // パッドするバイト長を取得
            int padLengthByte = lengthByte - GetByteCount(partialString);

            // パッドする必要がない場合
            if (padLengthByte == 0)
            {
                return partialString;
            }

            // パッドする長さを取得
            int padLength = padLengthByte / GetByteCount(padCharacter.ToString());

            return partialString.PadLeft(partialString.Length + padLength, padCharacter);
        }

        /// <summary>
        /// 文字列を指定されたバイト長に右詰めで成型します
        /// </summary>
        /// <param name="target">対象の文字列</param>
        /// <param name="lengthByte">バイト長</param>
        /// <param name="padCharacter">パッドキャラクター</param>
        /// <returns>指定されたバイト長に右詰めで成型された文字列</returns>
        /// <remarks>成型された文字列の末尾に全角文字途中の要素が混入している場合は除去し、パッドキャラクターを追加します</remarks>
        /// <remarks>Unicodeでバイト長に奇数が指定された場合などは、バイト長を超えない最大の長さで成型します</remarks>
        public string FormFixedByteLengthRight(string target, int lengthByte,
            char padCharacter)
        {
            return FormFixedByteLengthRight(target, lengthByte, padCharacter, true);
        }

        /// <summary>
        /// 文字列を指定されたバイト長に右詰めで成型します
        /// </summary>
        /// <param name="target">対象の文字列</param>
        /// <param name="lengthByte">バイト長</param>
        /// <returns>指定されたバイト長に右詰めで成型された文字列</returns>
        /// <remarks>成型された文字列の末尾に全角文字途中の要素が混入している場合は除去し、半角スペースを追加します</remarks>
        /// <remarks>Unicodeでバイト長に奇数が指定された場合などは、バイト長を超えない最大の長さで成型します</remarks>
        public string FormFixedByteLengthRight(string target, int lengthByte)
        {
            return FormFixedByteLengthRight(target, lengthByte, ’ ’);
        }
 
 
Clipボタンをクリックすると、「StringUtility」というクラスがコピーされます。このソースを「StringUtility.cs」ファイルにコピーするとすぐご利用いただけます。
 

.NET 文字列を指定されたバイト数に切り詰める

VBのLeftBやRightBに相当するメソッドを作成しました。
 
以前に投稿した「SubstringByteメソッド」を使用しますので、切り詰めた部分文字列が文字化けする場合は、文字化けした文字を除去します。
 
●左から切り詰める場合
StringUtility utility = new StringUtility();

utility.TruncateByteLeft("1あいうえお", 4);
実行結果:”1あ”
 
●右から切り詰める場合
StringUtility utility = new StringUtility();

utility.TruncateByteRight("1あいうえお", 4);
実行結果:”えお”
 
以下のエリアではTruncateByteLeftメソッドとTruncateByteRightメソッドを実際に動かした時の挙動を確認できます。
 
StringUtility utility = new StringUtility();

utility.TruncateByteLeft(
    
 ", 
 );
実行結果:
“”
 
StringUtility utility = new StringUtility();

utility.TruncateByteRight(
    
 ", 
 );
実行結果:
“”
 
※実行結果の半角スペースは「¸」で表します。
 
TruncateByteLeftメソッド、TruncateByteRightメソッドのソースコードは以下になります。
 
        /// <summary>
        /// 文字列を指定されたバイト長に左側から切り詰めます
        /// </summary>
        /// <param name="target">対象の文字列</param>
        /// <param name="lengthByte">バイト長</param>
        /// <returns>指定されたバイト長に切り詰めた文字列</returns>
        /// <remarks>
        /// <para>文字列が指定されたバイト長に満たない場合は、成型せずに返します</para>
        /// <para>切り詰めた文字列の末尾に全角文字途中の要素が混入している場合は除去します</para>
        /// </remarks>
        public string TruncateByteLeft(string target, int lengthByte)
        {
            // 対象の文字列のバイト長が指定されたバイト長以下の場合
            if (GetByteCount(target) <= lengthByte)
            {
                return target;
            }

            return SubstringByte(target, 0, lengthByte);
        }

        /// <summary>
        /// 文字列を指定されたバイト長に右側から切り詰めます
        /// </summary>
        /// <param name="target">対象の文字列</param>
        /// <param name="lengthByte">バイト長</param>
        /// <returns>指定されたバイト長に切り詰めた文字列</returns>
        /// <remarks>
        /// <para>文字列が指定されたバイト長に満たない場合は、成型せずに返します</para>
        /// <para>切り詰めた文字列の先頭に全角文字途中の要素が混入している場合は除去します</para>
        /// </remarks>
        public string TruncateByteRight(string target, int lengthByte)
        {
            // 対象の文字列のバイト長を取得
            int targetByteCount = GetByteCount(target);

            // 対象の文字列のバイト長が指定されたバイト長以下の場合
            if (targetByteCount <= lengthByte)
            {
                return target;
            }

            return SubstringByte(target, targetByteCount - lengthByte, lengthByte);
        }
 
 
Clipボタンをクリックすると、「StringUtility」というクラスがコピーされます。このソースを「StringUtility.cs」ファイルにコピーするとすぐご利用いただけます。
 

.NET 文字列からバイト単位で部分文字列を取得する

C#、VB.NETで半角を1バイト、全角を2バイトとして、指定したバイト数の部分文字列を取得する、SubstringByteメソッドを作成しました。
 
SubstringByteメソッドに「対象の文字列」、「開始位置のバイト(0から始まるインデックス)」、「部分文字列のバイト数」を指定し実行すると部分文字列を取得できます。
 
StringUtility utility = new StringUtility();

utility.SubstringByte("1あいうえお", 2, 6);
実行結果:”いう”
 
上記のように指定すると「あ」の後ろ半分から「え」の前半分までの6バイトの部分文字列を対象とし、文字化けする最初と最後の文字を除去した「いう」を返します。
 
半角を1バイト、全角を2バイトは文字エンコーディングに「シフトJIS」を指定した場合ですが、「.NET 文字列のバイト数を取得する」と同様に他の文字エンコーディングにも対応しております。
 
以下のエリアではSubstringByteメソッドを実際に動かした時の挙動を確認できます。
 
StringUtility utility = new StringUtility();

utility.SubstringByte(
    
 ", 
 , 
 );
実行結果:
“”
 
※実行結果の半角スペースは「¸」で表します。
 
SubstringByteメソッドのソースコードは以下になります。
 
        /// <summary>
        /// 文字エンコーディング
        /// </summary>
        private Encoding _myEncoding = Encoding.GetEncoding("Shift_JIS");

        /// <summary>
        /// 文字エンコーディング
        /// </summary>
        public Encoding MyEncoding
        {
            get
            {
                return this._myEncoding;
            }
        }

        /// <summary>
        /// 文字列からバイト単位で部分文字列を取得します
        /// </summary>
        /// <param name="target">対象の文字列</param>
        /// <param name="startIndexByte">開始位置インデックスバイト</param>
        /// <param name="lengthByte">部分文字列のバイト数</param>
        /// <returns>文字列からバイト単位で取得した部分文字列</returns>
        public string SubstringByte(string target, int startIndexByte, int lengthByte)
        {
            if (startIndexByte < 0)
            {
                throw new ArgumentOutOfRangeException(
                    "開始位置インデックスバイトが0未満です。");
            }

            if (lengthByte < 0)
            {
                throw new ArgumentOutOfRangeException(
                    "部分文字列のバイト数が0未満です。");
            }

            // 対象の文字列をバイト配列にする
            byte[] targetBytes = MyEncoding.GetBytes(target);

            // 開始位置インデックスバイト+部分文字列のバイト数が文字列のバイト数を超える場合
            if (targetBytes.Length < startIndexByte + lengthByte)
            {
                throw new ArgumentOutOfRangeException("開始位置インデックスバイトまたは部分文字列のバイト数の指定に誤りがあります。");
            }

            // 対象の文字列からバイト単位で部分文字列を取得
            string partialString = MyEncoding.GetString(
                targetBytes, startIndexByte, lengthByte);

            // 先頭に全角文字途中の要素が混入している場合は除去
            partialString = TrimHeadHalfwayDoubleByteCharacter(
                partialString, target, targetBytes, startIndexByte);

            // 末尾に全角文字途中の要素が混入している場合は除去
            partialString = TrimEndHalfwayDoubleByteCharacter(
                partialString, target, targetBytes, startIndexByte, lengthByte);

            return partialString;
        }

        /// <summary>
        /// 先頭に全角文字途中の要素が混入している場合は除去します
        /// </summary>
        /// <param name="partialString">部分文字列</param>
        /// <param name="target">対象の文字列</param>
        /// <param name="targetBytes">対象の文字列のバイト配列</param>
        /// <param name="startIndexByte">開始位置インデックスバイト</param>
        /// <returns>先頭の全角文字途中の要素を除去した部分文字列</returns>
        private string TrimHeadHalfwayDoubleByteCharacter(
            string partialString, string target, byte[] targetBytes, int startIndexByte)
        {
            // 部分文字列が空の場合
            if (partialString == string.Empty)
            {
                return partialString;
            }

            // 開始位置の要素を含む部分文字列を取得
            string leftString = MyEncoding.GetString(targetBytes, 0, startIndexByte + 1);

            // 部分文字列の先頭要素が一致する場合
            if (target[leftString.Length - 1] == partialString[0])
            {
                return partialString;
            }

            // 先頭の全角文字途中の要素を除去
            return partialString.Substring(1);
        }

        /// <summary>
        /// 末尾に全角文字途中の要素が混入している場合は除去します
        /// </summary>
        /// <param name="partialString">部分文字列</param>
        /// <param name="target">対象の文字列</param>
        /// <param name="targetBytes">対象の文字列のバイト配列</param>
        /// <param name="startIndexByte">開始位置インデックスバイト</param>
        /// <param name="lengthByte">部分文字列のバイト数</param>
        /// <returns>末尾の全角文字途中の要素を除去した部分文字列</returns>
        private string TrimEndHalfwayDoubleByteCharacter(
            string partialString, string target, byte[] targetBytes, int startIndexByte,
            int lengthByte)
        {
            // 部分文字列が空の場合
            if (partialString == string.Empty)
            {
                return partialString;
            }

            // 最終要素を含む部分文字列を取得
            string leftString = MyEncoding.GetString(
                targetBytes, 0, startIndexByte + lengthByte);

            // 部分文字列の最終要素が一致する場合
            if (target[leftString.Length - 1] == partialString[partialString.Length - 1])
            {
                return partialString;
            }

            // 末尾の全角文字途中の要素を除去
            return partialString.Substring(0, partialString.Length - 1);
        }
 
 
Clipボタンをクリックすると、「StringUtility」というクラスがコピーされます。このソースを「StringUtility.cs」ファイルにコピーするとすぐご利用いただけます。
 

.NET 文字列のバイト数を取得する

C#、VB.NETで半角を1バイト、全角を2バイトとして、文字列のバイト数を取得するGetByteCountメソッドを作成しました。
 
StringUtility utility = new StringUtility();

utility.GetByteCount("1あいうえお");
実行結果:11
 
半角を1バイト、全角を2バイトは文字エンコーディングに「シフトJIS」を指定した場合ですが、もちろん他の文字エンコーディングにも対応しております。
 
たとえば全ての文字を2バイトで表すUnicodeを指定した場合は、
 
StringUtility utility = new StringUtility(Encoding.Unicode);

utility.GetByteCount("1あいうえお");
実行結果:12
 
となります。
 
以下のエリアではGetByteCountメソッドを実際に動かした時の挙動を確認できます。
 
StringUtility utility = new StringUtility(
    
Encoding.GetEncoding(
 "));
 
utility.GetByteCount(
 ");
実行結果:
 
 
GetByteCountメソッドのソースコードは以下になります。
 
        /// <summary>
        /// 文字エンコーディング
        /// </summary>
        private Encoding _myEncoding = Encoding.GetEncoding("Shift_JIS");

        /// <summary>
        /// 文字エンコーディング
        /// </summary>
        public Encoding MyEncoding
        {
            get
            {
                return this._myEncoding;
            }
        }

        /// <summary>
        /// コンストラクタ
        /// </summary>
        public StringUtility()
        {
        }

        /// <summary>
        /// コンストラクタ
        /// </summary>
        /// <param name="encoding">文字エンコーディング</param>
        public StringUtility(Encoding encoding)
        {
            this._myEncoding = encoding;
        }

        /// <summary>
        /// 文字列のバイト数を取得します
        /// </summary>
        /// <param name="target">対象の文字列</param>
        /// <returns>文字列のバイト数</returns>
        public int GetByteCount(string target)
        {
            return MyEncoding.GetByteCount(target);
        }
 
 
Clipボタンをクリックすると、「StringUtility」というクラスがコピーされます。このソースを「StringUtility.cs」ファイルにコピーするとすぐご利用いただけます。
 

2進数、8進数文字列を整数に変換する

16進数文字列を整数に変換する」でご紹介した「Convert」クラスを利用すると、16進数だけではなく2進数や8進数の文字列も整数に変換することができます。
 
●2進数文字列 ⇔ 整数
Convert.ToInt32("10011010010", 2);
実行結果:
1234
 
Convert.ToString(1234, 2);
実行結果:
"10011010010"
 
●8進数文字列 ⇔ 整数
Convert.ToInt32("15205", 8);
実行結果:
6789
 
Convert.ToString(6789, 8);
実行結果:
"15205"
 
以下のエリアでは「Convert」クラスのメソッドを実際に動かした時の挙動を確認できます。
 
●2進数文字列 ⇒ 整数
Convert.ToInt32(" 
 ", 2);    
実行結果:
 
●整数 ⇒ 2進数文字列
Convert.ToString( 
 , 2);    
実行結果:
""
 
●8進数文字列 ⇒ 整数
Convert.ToInt32(" 
 ", 8);    
実行結果:
 
●整数 ⇒ 8進数文字列
Convert.ToString( 
 , 8);    
実行結果:
""
 

16進数文字列を整数に変換する

C#、VB.NETで16進数の文字列を整数に変換したり、整数を16進数の文字列に変換するには「Convert」クラスを使うと便利です。
 
●16進数文字列 ⇒ 整数
Convert.ToInt32("FFFF", 16);
実行結果:
65535
 
●整数 ⇒ 16進数文字列
Convert.ToString(65535, 16);
実行結果:
"ffff"
 
以下のエリアでは「Convert」クラスのメソッドを実際に動かした時の挙動を確認できます。
 
●16進数文字列 ⇒ 整数
Convert.ToInt32(" 
 ", 16);    
実行結果:
 
※16進数文字列にはプレフィクス「0x」をつけることができます。
 
●整数 ⇒ 16進数文字列
Convert.ToString( 
 , 16);    
実行結果:
""
g h T
 12,846 Total Views