(.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)
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行ずつ読み取ることができます。改行コードが混在する際に便利です。
参考: