忍者ブログ

VB.NET-TIPS などプログラミングについて

VB.NETのTIPS(小技集)を中心に、Javascript、PHP その他のプログラミングについて少し役に立つ情報を発信します。いわゆる個人的な忘備録ですが、みなさんのお役に立てれば幸いです。

バイト指定による文字列の切出しに付いて(MidB, LeftB, RightB)

あるデータ処理において文字列を Shift-JIS と考えて切出す必要があり、 文字列を Shift-JIS と見立てて切出す関数を作ってみましたので紹介します。

VB.NET において通常、文字列は Unicode(UTF-8) で処理されています。 ほとんどの場合は文字コードのことを特に考えなくても問題は無いのですが、まれにシリアル通信等で外部とのやり取りを行う場合に 文字列のコードが Shift-JIS を使っていたりします。こういった場合に今回の関数群は使えると思います。

では、最初に文字列の中から文字列のバイト位置(Shift-JISと考えて)と切出すバイト数を指定し、処理する関数である MidB(以前の VB では Mid$ とされていたもの)を記します。
開始位置、切出しバイト数の指定値により、全角文字の泣き別れが発生しますので、関数の処理手順は以下の様に行います。

  • 開始位置が「1」未満の場合は空文字を返す。
  • 文字列をShift-JISエンコードでバイト配列に分解し、開始位置が配列の長さより大きい場合は空文字を返す。
  • 先頭から見て指定位置の直前までを切出し最後の文字が漢字の左半分の場合、開始位置と切出しバイト数を調整。
  • 調整された開始位置とバイト数で文字列を切出し最後の文字が漢字の左半分の場合、切出しバイト数を調整。
  • 調整された開始位置とバイト数で文字列を生成する。

MidB 関数

''' 
''' 開始位置、バイト指定による文字列切出・Mid関数
''' 
''' <param name="astrSrc">対象文字列</param>
''' <param name="aintStart">開始位置(先頭1から)</param>
''' <param name="aintLen">切出しバイト数</param>
''' 切出し文字列
Private Function MidB(ByVal astrSrc As String, 
                      ByVal aintStart As Integer,
                      ByVal aintLen As Integer) As String
    Try
        '開始を「0」からの指標
        Dim intStart As Integer = aintStart - 1
        '開始が1より小さい場合は空文字を返す
        If intStart < 0 Then
            Return ""
        End If
        'Shift-JISでエンコーディングしてバイト配列に分解
        Dim objEnc As System.Text.Encoding =
                      System.Text.Encoding.GetEncoding("Shift_JIS")
        Dim arrBytes As Byte() = objEnc.GetBytes(astrSrc)
        '開始がバイト配列より大きい場合は空文字を返す
        If intStart > arrBytes.Length - 1 Then
            Return ""
        End If

        '取り出しバイト数
        Dim intLen As Integer = aintLen
        If (intStart + aintLen) > (arrBytes.Length - 1) Then
            intLen = arrBytes.Length - intStart
        End If

        '先頭から見て指定位置の直前までを切り出す
        Dim strTemp As String = objEnc.GetString(arrBytes, 0, intStart)
        If strTemp.EndsWith(ControlChars.NullChar) Or strTemp.EndsWith("・") Then
            '最後の文字が漢字の左半分の場合、切出の先頭は泣き別れになる
            intStart += 1   '開始位置を右へ
            intLen -= 1     '切出バイト数を1個少なくする
        End If

        '修正位置とバイト数で切り出す
        strTemp = objEnc.GetString(arrBytes, intStart, intLen)
        If strTemp.EndsWith(ControlChars.NullChar) Or strTemp.EndsWith("・") Then
            '最後の文字が漢字の左半分の場合、泣き別れになる
            intLen -= 1     '切出バイト数をさらに1個少なくする
        End If

        '文字列を返す
        Return objEnc.GetString(arrBytes, intStart, intLen)

    Catch ex As Exception
        Return ""
    End Try
End Function

以前の VBMid$ では第3引数が無く、開始位置から右側を全て返す関数がありましたので、 同じ関数名で引数の数が異なる関数を以下に記します。

MidB 関数(開始位置以降の切出し)

''' 
''' 開始位置以降の文字列切出・Mid関数
''' 
''' <param name="astrSrc">対象文字列</param>
''' <param name="aintStart">開始位置(先頭1から)</param>
''' 切出し文字列
Private Function MidB(ByVal astrSrc As String, ByVal aintStart As Integer) As String
    Try
        '開始を「0」からの指標
        Dim intStart As Integer = aintStart - 1
        '開始が1より小さい場合は空文字を返す
        If intStart < 0 Then
            Return ""
        End If
        'Shift-JISでエンコーディングしてバイト配列に分解
        Dim objEnc As System.Text.Encoding =
                      System.Text.Encoding.GetEncoding("Shift_JIS")
        Dim arrBytes As Byte() = objEnc.GetBytes(astrSrc)
        '開始がバイト配列より大きい場合は空文字を返す
        If intStart > arrBytes.Length - 1 Then
            Return ""
        End If

        '実際の処理は上記の関数をコール
        Return MidB(astrSrc, aintStart, arrBytes.Length - aintStart + 1)

    Catch ex As Exception
        Return ""
    End Try
End Function

さらに、文字列の左側から指定バイト数を切り出す LeftB 関数、文字列の右側から指定バイト数を切り出す RightB 関数を記します。 この2個の関数は最初の MidB 関数を利用しています。

LeftB 関数 , RightB 関数

''' 
''' バイト数指定による文字列の左側切出し・Left関数
''' 
''' <param name="astrSrc">対象文字列</param>
''' <param name="aintLen">左側切出しバイト数</param>
''' 切出し文字列
Private Function LeftB(ByVal astrSrc As String, ByVal aintLen As Integer) As String
    '先頭から指定バイト数を切り出す
    Return MidB(astrSrc, 1, aintLen)
End Function

''' 
''' バイト数指定による文字列の右側切出し・Right関数
''' 
''' <param name="astrSrc">対象文字列</param>
''' <param name="aintLen">右側切出しバイト数</param>
''' 切出し文字列
Private Function RightB(ByVal astrSrc As String, ByVal aintLen As Integer) As String
    'Shift-JISでエンコーディングしてバイト配列に分解
    Dim objEnc As System.Text.Encoding = System.Text.Encoding.GetEncoding("Shift_JIS")
    Dim arrBytes As Byte() = objEnc.GetBytes(astrSrc)
    'バイト数がバイト配列の個数より多い場合は、対象文字列そのまま返す
    If aintLen >= arrBytes.Length Then
        Return astrSrc
    End If
    '開始位置
    Dim intStart As Integer = arrBytes.Length - aintLen + 1
    '先頭から指定バイト数を切り出す
    Return MidB(astrSrc, intStart, aintLen)
End Function

これらの関数を実行する例を以下に記します。 これはフォームにボタンを設置し、クリックイベント時に、各関数の処理を行い結果をデバッグ用の出力ウインドウに表示しています。

    Private Sub btnStringCut_Click(sender As Object, e As EventArgs) Handles btnStringCut.Click
        '表示
        Dim strSrc As String = "あいうえお"
        Dim i As Integer

        '引数が3個ある MidB 関数
        Dim nCut As Integer = 6
        For i = 0 To 10
            Dim strDes As String = MidB(strSrc, i, nCut)
            Console.WriteLine("MidB(""{0}"", {1}, {2}) : /{3}/", strSrc, i, nCut, strDes)
        Next

        '引数が2個の MidB 関数
        For i = 0 To 10
            Dim strDes As String = MidB(strSrc, i)
            Console.WriteLine("MidB(""{0}"", {1}) : /{2}/", strSrc, i, strDes)
        Next

        'LeftB 関数
        For i = 0 To 10
            Dim strDes As String = LeftB(strSrc, i)
            Console.WriteLine("LeftB(""{0}"", {1}) : /{2}/", strSrc, i, strDes)
        Next

        'RightB 関数
        For i = 1 To 11
            Dim strDes As String = RightB(strSrc, i)
            Console.WriteLine("RightB(""{0}"", {1}) : /{2}/", strSrc, i, strDes)
        Next
    End Sub

結果の表示は以下の通りです。

MidB("あいうえお", 0, 6) : //
MidB("あいうえお", 1, 6) : /あいう/
MidB("あいうえお", 2, 6) : /いう/
MidB("あいうえお", 3, 6) : /いうえ/
MidB("あいうえお", 4, 6) : /うえ/
MidB("あいうえお", 5, 6) : /うえお/
MidB("あいうえお", 6, 6) : /えお/
MidB("あいうえお", 7, 6) : /えお/
MidB("あいうえお", 8, 6) : /お/
MidB("あいうえお", 9, 6) : /お/
MidB("あいうえお", 10, 6) : //
MidB("あいうえお", 0) : //
MidB("あいうえお", 1) : /あいうえお/
MidB("あいうえお", 2) : /いうえお/
MidB("あいうえお", 3) : /いうえお/
MidB("あいうえお", 4) : /うえお/
MidB("あいうえお", 5) : /うえお/
MidB("あいうえお", 6) : /えお/
MidB("あいうえお", 7) : /えお/
MidB("あいうえお", 8) : /お/
MidB("あいうえお", 9) : /お/
MidB("あいうえお", 10) : //
LeftB("あいうえお", 0) : //
LeftB("あいうえお", 1) : //
LeftB("あいうえお", 2) : /あ/
LeftB("あいうえお", 3) : /あ/
LeftB("あいうえお", 4) : /あい/
LeftB("あいうえお", 5) : /あい/
LeftB("あいうえお", 6) : /あいう/
LeftB("あいうえお", 7) : /あいう/
LeftB("あいうえお", 8) : /あいうえ/
LeftB("あいうえお", 9) : /あいうえ/
LeftB("あいうえお", 10) : /あいうえお/
RightB("あいうえお", 1) : //
RightB("あいうえお", 2) : /お/
RightB("あいうえお", 3) : /お/
RightB("あいうえお", 4) : /えお/
RightB("あいうえお", 5) : /えお/
RightB("あいうえお", 6) : /うえお/
RightB("あいうえお", 7) : /うえお/
RightB("あいうえお", 8) : /いうえお/
RightB("あいうえお", 9) : /いうえお/
RightB("あいうえお", 10) : /あいうえお/
RightB("あいうえお", 11) : /あいうえお/

関連する記事

文字列の連結をStringBuilderで高速に行う(StringBuilder)
SerialPortコントロールの使い方その3(外部装置からの垂れ流しデータ受信)











PR

コメント

コメントを書く