テキストファイル入出力―その2
相関係数の計算
テキストファイルからデータを読み込み、計算結果などをテキストファイルへ書き出すプログラムを作成した。データのテキストファイルは図1のような形式である。

図1
行の先頭がスラッシュ/で始まる行に挟まれて、データが1行に2つずつペアで書かれている。データの読み込みのときは、このスラッシュ/で始まる行まで読み飛ばし、次のスラッシュ/で始まる行までデータを各行から1つのペアずつ読み込んでいく。
プログラムの作成は、まずメニュ「ファイル|新規作成|プロジェクト」を選ぶ(図2)。

図2
表示されたダイアログボックス(図3)でプロジェクトの種類「CLR」、テンプレート「Windowsフォームアプリケーション」を選択する。

図3
フォームのデザインは、Buttonを2個、Labelを1個、図4のように配置する。さらにOpenFileDialogとSaveFileDialogを用意する。

図4
コードは以下のように用意する。
#pragma endregion
private: System::Void
buttonClose_Click(System::Object^
sender, System::EventArgs^
e) {
Close();
}
private: System::Void
buttonGO_Click(System::Object^
sender, System::EventArgs^
e) {
openFileDialog1->FileName = "*.txt";
if
(openFileDialog1->ShowDialog() != System::Windows::Forms::DialogResult::OK){
label1->Text = "openFileDialog is canceled";
return;
}
try {
FileStream ^ fs = gcnew FileStream(openFileDialog1->FileName, FileMode::Open);
StreamReader ^ fin = gcnew StreamReader(fs,
System::Text::Encoding::GetEncoding("Shift-JIS"));
saveFileDialog1->FileName = "";
if
(saveFileDialog1->ShowDialog() != System::Windows::Forms::DialogResult::OK){
label1->Text = "saveFileDialog is canceled";
return;
}
fs = gcnew
FileStream(saveFileDialog1->FileName,FileMode::Create);
StreamWriter ^ fout = gcnew StreamWriter(fs);
String ^ s;
s = "Data
File..." + openFileDialog1->FileName;
fout->WriteLine(s);
int ck =
0;
do {
s = fin->ReadLine()->Trim();
if
(s->Length > 0){
if (s[0] == '/')
ck = 1;
}
} while
(ck == 0);
double x[1000],
y[1000];
double
sumX = 0.0,
double
meanX, meanY;
int n =
0;
for (;;)
{
s = fin->ReadLine();
if (s[0]
== '/') break;
n++;
s = s->Trim();
x[n-1] = XmlConvert::ToDouble(extract_data(s,0));
y[n-1] =
XmlConvert::ToDouble(extract_data(s,1));
sumX += x[n-1];
}
meanX = sumX/n;
meanY = sumY/n;
s = "入力データ...";
fout->WriteLine(s);
for (int i = 0; i < n; i++){
s = "X["
+ (i+1).ToString() + "] = " +
x[i].ToString() +
" Y[" +
(i+1).ToString() + "] = " +
y[i].ToString();
fout->WriteLine(s);
}
fout->WriteLine("");
fout->WriteLine("平均値(X) = " + meanX.ToString() +
"
平均値(Y) = " + meanY.ToString());
double
sumXX = 0.0, sumYY = 0.0, sumXY = 0.0;
for (int i = 0; i < n; i++){
sumXX += (x[i]-meanX)*(x[i]-meanX);
sumYY +=
(y[i]-meanY)*(y[i]-meanY);
sumXY +=
(x[i]-meanX)*(y[i]-meanY);
}
double
SDx1 = Math::Sqrt(sumXX/(n-1));
double
SDy1 = Math::Sqrt(sumYY/(n-1));
double
cov = sumXY/n;
double SDx = Math::Sqrt(sumXX/n);
double
SDy = Math::Sqrt(sumYY/n);
double
r = cov/(SDx*SDy);
fout->WriteLine("標準偏差(X) = " + SDx1.ToString("0.#####E0") +
" 標準偏差(Y) =
"
+ SDy1.ToString("0.#####E0") );
fout->WriteLine("共分散= " + cov.ToString("0.#####E0") );
fout->WriteLine("相関係数= " + r.ToString("0.#####"));
fin->Close();
fout->Close();
label1->Text = "Output File..." + saveFileDialog1->FileName;
}
catch
(Exception ^ e1) {
label1->Text = "Err..." + e1;
return;
}
return;
}
関数extract_dataはインクルードファイルmyLib.hとして以下のように用意して、Form1.hと同じフォルダ内に置いている。
namespace MyLib {
using namespace
System; // Stringクラス用
/*
文字列sにおいて空白で区切られた部分文字列の
n_p番目の部分文字列を返す。
部分文字列は0番目から数える。
By
Y. Okamoto, 2006,8
*/
String
^ extract_data( String^ s, int n_p ) {
if (n_p < 0) return
"";
s = s->Trim();
int ck;
int s_p =
0;
int e_p;
if (s == "") return
"";
// s_pをn_p番目の部分文字列の先頭位置に設定する
if (n_p
> 0) {
for (int i = 0; i < n_p; i++) {
ck =
0;
do {
s_p++;
if (s_p
>= s->Length) { ck = 9; }
else {
if (s[s_p]
== ' ') { ck = 1; };
};
} while
(ck == 0);
if (ck ==
9) return "";
while
(s[s_p] == ' ') s_p++;
}
}
// e_sをn_p番目の部分文字列の最後尾の次の位置に設定する
e_p = s_p;
ck = 0;
do
{
e_p++;
if
(e_p >= s->Length) {ck = 9;}
else
{
if
(s[e_p] == ' ') ck = 1;
}
} while
(ck == 0);
// 求める部分文字列を返す
return
s->Substring(s_p, e_p-s_p);
}
}
この関数extract_dataは、与えられた文字列内において任意個の空白(半角文字)で区切られた文字列のグループからn_p番目のグループを取り出すものである。グループは0番目から数える。
このヘッダーファイルmyLib.hのインクルード、およびファイルストリームを用いるために名前空間System::IO、文字列をその表す実数値に変換する関数ToDoubleを用いるために図5のようにincludeとusing namespaceの使用を宣言しておく。

図5
プログラムを実行すると図6のフォームが表示される。

図6
「GO」ボタンをクリックすると図7のように入力データファイル名の設定を求めるダイアログボックスが表示される。

図7
図1の形式で用意してあるテキストファイル名を設定後「開く」ボタンをクリックすると、出力ファイル名の設定を求めるダイアログボックスが表示される(図8)。

図8
適当な出力用ファイル名を設定して「保存」ボタンをクリックすると指定したファイル名のテキストファイルに書き込みが始まり、終了後図9のように「Output File…」のメッセージが表示される。

図9
フォームとメッセージの長さの関係が気になるときは、フォームの端をドラッグすることにより調整できる(図10)。

図10
「Close」ボタンをクリックするとプログラムの実行終了となる。プログラムの終了後、書き込まれたファイルを開くと図11のようになっている。

図11
プログラムのソースファイルは圧縮ファイルcor.ZIPとして用意した。ここをクリックしてダウンロードすることができる。