3流プログラマのメモ書き

元開発職→社内SE→派遣で営業支援の三流プログラマのIT技術メモ書き。 このメモが忘れっぽい自分とググってきた技術者の役に立ってくれれば幸いです。(jehupc.exblog.jpから移転中)

(.Net)RichTextBoxコントロールは勝手に改行コードをLF(ラインフィード)にしてしまう!?

またMicrosoftの陰謀の話です。

(VB.Net)DataObject.GetText()の引数にCSV(TextDataFormat.CommaSeparatedValu)指定時のバグ!? で上げたコードを使ってCSV出力時にセル値の改行コードを取り除く処理をやろうと思ったのですが、なぜか改行が出力されてしまうという現象に出くわしました。

ちなみに、セル値の改行コードを取り除く処理は下記のようにしています。

cell.Value = (cell.Value.ToString()).Replace(vbNewLine, "")

で、どうやらこの原因がデータ入力時に用いているRichTextBoxだということまで至るのに大変時間がかかりました。

RichTextBoxコントロールのMultilineプロパティがTrueなら複数行入力できるのですが、その改行コードが勝手にLF(ラインフィード)にされてしまうのです。

下記のようにコード上から CRLF の文字列を入れても RichTextBox.Text プロパティで取得すると LF だけになってるのです。

Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click

'意図的に RichTextBox1 と TextBox1 の双方に CRLF を含んだ文字列を代入

RichTextBox1.Text = "ABC" & vbNewLine & "あ" & vbNewLine

TextBox1.Text = "ABC" & vbNewLine & "あ" & vbNewLine

 

Console.Write("RichTextBox:")

' RichTextBox1.Text文字列をダンプ

DumpString(RichTextBox1.Text)

 

Console.Write("TextBox :")

' TextBox1.Text文字列をバイト配列に変換

DumpString(TextBox1.Text)

End Sub

 

Private Sub DumpString(ByVal str As String)

' エンコーディングUnicode

Dim sourceEncoding As System.Text.Encoding = System.Text.Encoding.Unicode

'文字列をバイト型配列に変換

Dim bytAry As Byte() = sourceEncoding.GetBytes(str)

For Each value As Byte In bytAry

'16進数2桁でコンソールに出力

Console.Write("{0:X2} ", value)

Next

Console.WriteLine()

End Sub

この結果は下記のようになります。(結果はリトルエンディアンで表示されている)

RichTextBox:41 00 42 00 43 00 0A 00 42 30 0A 00

TextBox :41 00 42 00 43 00 0D 00 0A 00 42 30 0D 00 0A 00

TextBoxのほうは 0x000D 0x000A(CRLF) となっているのに、RichTextBoxは 0x000A(LF) しかありません。

MSDNライブラリには特に明記されていないのでやはりバグでしょうか。それともMS得意の仕様?

ということで、RichTextBoxからTextプロパティで値を取得した後に、LF だけの改行コードを CRLF に直すメソッドを作ってみました。

Private Function Lf_To_CrLf(ByVal src As String) As String

'文字列がnullか空文字の場合

If String.IsNullOrEmpty(src) Then

Return String.Empty

End If

Dim sr As New IO.StringReader(src)

Dim line As String

Dim out As New System.Text.StringBuilder

Do

'StringReader.ReadLine()を使うと3種類の改行コードいずれであっても1行ずつ読み出すことができる。

line = sr.ReadLine()

If line is Nothing Then Exit Do

out.Append(line)

out.Append(vbNewLine)

Loop

'元の文字列に改行がない場合は、上のループでつけた最後の改行コードを削除

If src.Length > 2 AndAlso Not src(src.Length - 1) = vbLf Then

out = out.Remove(out.Length - 2, 2)

End If Return out.ToString()

End Function

このメソッドを最初のコードにつけくわてみます。

Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click

RichTextBox1.Text = "ABC" & vbNewLine & "あ" & vbNewLine

TextBox1.Text = "ABC" & vbNewLine & "あ" & vbNewLine

 

Console.Write("RichTextBox:")

' RichTextBox1.Text文字列をダンプ

DumpString(RichTextBox1.Text)

 

Console.Write("TextBox :")

' TextBox1.Text文字列をバイト配列に変換

DumpString(TextBox1.Text)

 

Console.Write("Lf_To_CrLf :")

'LFをCRLFに変換

DumpString(Lf_To_CrLf(RichTextBox1.Text))

End Sub

結果はこうなります。

RichTextBox:41 00 42 00 43 00 0A 00 42 30 0A 00

TextBox :41 00 42 00 43 00 0D 00 0A 00 42 30 0D 00 0A 00

Lf_To_CrLf :41 00 42 00 43 00 0D 00 0A 00 42 30 0D 00 0A 00

ちゃんと L Fが CRLF になってますね。

ちなみに、StringReader.ReadLineメソッドを使うとどの改行コードでも関係なく1行ずつ読み取ることができます。改行コードが混在する際に便利です。

参考:

複数の行を含む文字列から1行ずつ読み出すには?