Windowsの改行コードの扱いについて質問させていただきます。
dc.DrawText(_T(あああ\nいいい), CRect(0, 0, 100, 100), 0);
dc.DrawText(_T(あああ\r\nいいい), CRect(0, 100, 100, 200), 0);
AfxMessageBox(_T(あああ\nいいい));
AfxMessageBox(_T(あああ\r\nいいい));
上記の二つの例は、\nだろうが\r\nだろうが、どちらでもちゃんと改行されます。
ただ、複数行のエディットボックスでは、\r\nとしないと改行されません。
となると、DrawText()やMessageBox()が\nでも改行されるのは、
その関数が気を利かせているだけで、本来は\r\nとするべきなのでしょうか?
ただ、そうなると、ファイルを読み書きするのに使うテキストモードというものは、
どういうときに使うのかという疑問もあります。
テキストモードがある以上、
プログラム内の文字列の改行は\nでよいのかと思っていたのですが、
エディットボックスだけはそうはいかず、
「エディットボックスに出すものはバイナリモードで読み書きする」とか、
「テキストモードで読んだものをエディットボックスに出すときは変換する」
みたいな回りくどい処理になってしまいます。
このへんの改行の扱いに詳しいかたはいらっしゃいませんでしょうか。
あんまり詳しくないですが…
WINDOWSでは標準の改行コードはCR+LFなので、DrawTextやMessageBoxにおいても\r\nで
指定すべきでしょう。
>ただ、そうなると、ファイルを読み書きするのに使うテキストモードというものは、
>どういうときに使うのかという疑問もあります。
NORさんのおっしゃる通り、ファイルを読み書きするときに使います。
テキスト出力の際、OSによって改行コードに差異があります。
それを吸収するために、\nと打てば、OSに対応した改行コードに変換してくれます。
この機能によってプログラムの移植が楽になるわけです。(OS変えるたびにプログラム中
の改行コードを変更するのはめんどくさい。)
>エディットボックスだけはそうはいかず、
>「エディットボックスに出すものはバイナリモードで読み書きする」とか、
>「テキストモードで読んだものをエディットボックスに出すときは変換する」
>みたいな回りくどい処理になってしまいます。
回りくどいですかね?
前者についてはバイナリモードで読み込んだものをそのまま出力するだけですし、
後者については一行ずつ出力して、その際に末尾に\r\nを追加するだけです。
どのように回りくどいのか、状況を具体的にすればよいアドバイスがもらえると思いま
す。
> どのように回りくどいのか、状況を具体的にすればよいアドバイスがもらえると思います。
具体的な処理が面倒というよりは、
どういうときにテキストモードを使うのかがわからなくなってしまいました。
エディットボックスだろうがメッセージボックスだろうが、
Windows上で文字列を扱うときには\r\nで処理するべきとなると、
テキストモードで読み込んで\nに変換した文字列は
どういうときに使うのかと疑問に思いました。
たとえば、テキストファイルの中身をエディットボックスやメッセージボックスに
表示するようなシンプルなプログラムの場合、
いったんテキストモードで読み込んで、再度\nを\r\nに自前で変換してから
使用するべきということでしょうか?
それとも、バイナリモードで\r\nのまま読み込むべきなのでしょうか?
大昔の話になりますが、GUIでなかった頃のOSはその仕様上
・キーボードからの入力とファイルからの入力
・画面出力とファイル出力
の間に互換性がありました。相互に置換可能だったわけですね。
初期のC言語はこれらのOSを前提としていたため、
入力元を特定したくない(ファイルでもキーでもOKにしたい)場合
には、互換モードである「テキストモード」が使用されました。
さて、
>どういうときにテキストモードを使うのかがわからなくなってしまいました。
についてですが、「テキストモード」が、
fopen( fname, t)や
_open( fname, _O_TEXT);
等を意味するのであれば、これらは一般的にはあまり使用されません。
そもそもfopen()自体をあまり使いません。
理由は、GUI時代に入り、また、文字コードの定義が変更されたりして
1.「テキスト」が何を意味するのか特定が困難になった。
例) 文字コードの問題:ASCII/SHIFT-JIS、UTF-8・・・色々と種類がある。
改行コードの問題:本件の様なことですね。
2.「標準」出力、入力にほとんど意味がなくなった。
3.当然それらの互換性を保持する意味も無くなった。
かつて16bitのWindows時代にはこれらの「標準」入出力系の関数が一切
使えなかったことも原因かもしれません。
余禄ですが、「出力」に関してはプリンターでさえ互換性がありましたが、
実は初期のコンピュータの出力とはこっちが標準だったりしたのです
(そもそも、モニターディスプレイが無かったりする)。
もちろん「テキストモード」であれば、プログラムを変更することなく、
これらの「みなしファイル」に対して出力ができました。
RS-232CもCOMという名前の「みなしファイル」とすることができました。
さらに、余禄ですが、データベース系の宣言型言語(SQLとか)などは、
全てテキストで命令するようになってますが、前述の通り
十分な環境的合理性があったのです(今は無し)。
うーーん、
まぁー PC-DOS/V, NEC版MS-DOSが主流だったころはASCII/SHIFT-JISが主流でした。
CR/LFの件ですが、CRは「CARRIAGE RETURN」ですよね。
LFは、LineFeed改行コードです。
CRの本来の機能は「行頭復帰」ですが、多分BASIC/C 言語のときに改行まで出来るよ
うになりました。
となると、テキストファイルの改行は「CR」か「LF」で悩んで最終的に「CR/LF」が
主流になったのだと思います。
いまだに一部のテキスト形式ファイル (Hexファイルやデーターベースの入出力ファ
イル等)は、他と切り分けられるように「LF」のみのもあります。
訂正です
>多分BASIC/C 言語のときに改行まで出来るようになりました。
多分BASIC/C 言語のときに改行まで出来るようになったのだと思います。
キャリッジリターンが\rで
ラインフィードが\nだったはずで
そう考えるとITOさんが書かれていることは逆な気がします。
キャリッジリターンはすでに書かれている通り行頭復帰ですから
これだけだと改行は行われずに今日の先頭にカーソルが移動するだけです。
で、ラインフィードが改行なのでそのままの意味にとると行を変えるだけなので
行末の位置で次の行にカーソルが移動するだけという話になります。
ですが、通常のコンソール入力において改行のみで復帰がないケースが
ないというのは多分わかると思います。
そんなこんなで基本的には改行に復帰も含まれているような動きになってます。
\r\nでも\nでも動きが変わらないのはそんな理屈からではないかと思います。
Windowsのテキストファイルの行末が\r\nというコードになっているのは
単純にこれまでの歴史的な背景があって互換と保つためという話ですね。
unix系だと改行コードがLFになっているもわりと有名かと。
あうあう。
誤)
これだけだと改行は行われずに今日の先頭にカーソルが移動するだけです。
正)
これだけだと改行は行われずに行の先頭にカーソルが移動するだけです。
> キャリッジリターンが\rで
> ラインフィードが\nだったはずで
> そう考えるとITOさんが書かれていることは逆な気がします。
確かに、\rがキャリッジリターンですね。
となると逆ですね。
失礼しました。
すみません、ちょっとまだ混乱しています。
fopen()を直接ではなく、MFCのCStdioFileでテキストファイルを読み込んでいます。
ただ、CStdioFile自体、内部でfopen()を使っているとかだったと思います。
(ひょっとしてCStdioFile自体がもはや時代遅れ?)
たとえば、テキストファイルを読み込んで、
複数行エディットボックスとメッセージボックスに出す場合、
どれが正しい方法になるのでしょうか?
1.
CFile::typeTextで読み込む
↓
読み込んだ文字列を自前で\n→\r\nに置換してからエディットボックスに表示
↓
読み込んだ文字列を\nのままメッセージボックスに表示
2.
CFile::typeTextで読み込む
↓
読み込んだ文字列を自前で\n→\r\nに置換してからエディットボックスに表示
↓
読み込んだ文字列を自前で\n→\r\nに置換してからメッセージボックスに表示
3.
CFile::typeBinaryで読み込む
↓
読み込んだ文字列を\r\nのままエディットボックスに表示
↓
読み込んだ文字列を\r\nのままメッセージボックスに表示
4.
CFile::typeBinaryで読み込む
↓
読み込んだ文字列を\r\nのままエディットボックスに表示
↓
読み込んだ文字列を自前で\r\n→\nに置換してからメッセージボックスに表示
一般的な話でいうなら
読み込むファイルがテキストファイルで行端がCR+LFなら
テキストモードで読み込んで\nのまま表示でよいはずです。
\r\nと\nが同じ動きになっているのは結果的のそうなっていると言う話であって
\nで改行も復帰も出来ているわけなので\rは余計だと思います。
読み込むテキストファイルの行端が決まっていない状態なら
バイナリモードで読み込んで読み込んだデータに対して走査して行端を検知することに
なると思います。
画面上の表示は基本的に\nで十分です。
\r\nにしなければいけない理由はないと思います。
結果的に同じ動きになっていると言う部分が理解できればわかると思います。
エディットボックスのケースのように特殊な場合だけ対応で良いような気もしますが、
結局の所、開発者の設計しだいと言うことではないでしょうか。
複数エディットボックスでの処理がアプリのメイン処理でその部分の処理を
軽減したいならメモリ上でも\r\nの方が楽に処理が出来るかもしれません。
但し、この場合は改行文字が2バイトになってしまうのでその点に注意が必要になりま
す。
データとして扱うなら改行も1バイトの方が扱いやすい場面があるかもしれません。
この辺は内部の実装とか提供する機能の内容にもよるので外野からどうこうは言いにく
いです。
最終的にはアプリケーションを組む時にいかに無駄が出にくい状態にするかなので実際
にはケース・バイ・ケースですとしか言いようがないです。
'\n'か'\r''\n'かを迷うのなら、一度'\0'にしてすべて変数に代入してしまう
やりかたもありますね。
そうすれば、エディットボックスは、'\n'をつければいいし、テキストファイルは
顧客の要望に会わせて'\n'もしくは'\r\n'にすればいいと思います。
保存時に選択させることもできますね。