Perl:テキストファイルのソートについて

[上に] [前に] [次に]
Weasel 2000/03/11(土) 23:03:53
間抜けな質問をご勘弁下さい。

ユーザーからアンケートを入力(toko.cgi)してもらい、
それをCSV形式(data.csv)に保存して、そのデータを表示させる
CGI(view.cgi)をPerlで作っています。
#()内はファイル名

その際、view.cgiには次のように記述してあります。

> open(OUT, "data.csv");
> while ($csv_line = <OUT>) {
> @data_view = split(/,/,$csv_line);
> print "<tr>";
> print  "<td bgcolor=\"#ffffdd\">$data_view[0]<\/td>";
> print  "<td bgcolor=\"#ffffdd\">$data_view[1]<\/td>";
> print  "<td bgcolor=\"#ffffdd\">$data_view[3]<\/td>";
> print  "<td bgcolor=\"#ffffdd\">$data_view[2]<\/td>";
> print  "<\/tr><\/table>";
> }
close(OUT);

こんな感じですが、送信されたデータを、新しい順に表示させる必要があるのです。
様々な事情があって、書き込まれるCSVファイルは、古い順番(下に追記)に
書き込まれる必要があるのです。

このラウンジを検索した結果、配列をソートさせる方法は分かったのですが、
読み込んだテキストファイルの内容をソートさせる方法がよくわからないのです。

http://www.tohoho-web.com/lng/199712/97120401.htm

> ちなみに、perlでテキストファイルの内容をソートするのなら、
> open(IN, "file.txt");
> print sort(<IN>);
> close(IN);
> でできるぞ。

とあったのですが、この場合どこに、この関数を記述すればよいのでしょうか?

以上、よろしくお願いいたします。

S-pore [HomePage] 2000/03/12(日) 00:46:58
ソートっていうか,データファイルの逆順に表示させたいわけですよね?

open(OUT, "data.csv");
print "<table>\n";
foreach (reverse(<OUT>))
{
  print "<tr>";
  foreach ((split(/,/))[0, 1, 3, 2])
  { print "<td bgcolor=\"#ffffdd\">$_</td>"; }
  print "</tr>\n";
}
print "</table>\n";
close(OUT);

この方法だとデータファイルが巨大な場合はメモリ喰いになりますが・・・。

andi 2000/03/12(日) 09:06:48
../199804/98040066.htm

「perlでレコードを逆から読むには?」という話題です。
tailで検索すると色々と出てきます。

Weasel 2000/03/12(日) 16:09:37
ありがとうございます。
早速下記のような形でやってみました。

> open(OUT, "tail -r data.csv |");
> while ($csv_line = <OUT>) {
> @data_view = split(/,/,$csv_line);
> print "<tr>";
> print"<td bgcolor=\"#ffffdd\">$data_view[0]<\/td>";
> print"<td bgcolor=\"#ffffdd\">$data_view[1]<\/td>";
> print"<td bgcolor=\"#ffffdd\">$data_view[3]<\/td>";
> print"<td bgcolor=\"#ffffdd\">$data_view[2]<\/td>";
> print"<\/tr><\/table>";
> }
> close(OUT);

あれ、テーブルの中が表示されなくなりました。
Win系のサーバーだと問題が生じる、みたいなことが
別のスレッド(tailで検索)に書いてありましたが、
うちはLinuxを使っています。

アドバイスお願いします。

Weasel 2000/03/12(日) 18:10:21
> この方法だとデータファイルが巨大な場合はメモリ喰いになりますが・・・。

現在、データファイルは6,311バイトです。多くても10Kを超す
ことはないと思いますが、どのくらいが「巨大な場合」に
なるのでしょうか?
#サーバーのシステムによって異なるとは思いますが、、、

Weasel 2000/03/12(日) 18:34:15
S-poreさんの教えていただいた方法でできました。
ありがとうございます。

しかし、ちょっと改良したい点があります。
一番最初のスクリプトでは
> print"<td bgcolor=\"#ffffdd\">$data_view[0]<\/td>";
> print"<td bgcolor=\"#ffffdd\">$data_view[1]<\/td>";
> print"<td bgcolor=\"#ffffdd\">$data_view[3]<\/td>";
> print"<td bgcolor=\"#ffffdd\">$data_view[2]<\/td>";
とやっていたので、セルごとに色を変えたり、nowrapを
かけたり、といったことができるのですが、この方法では
ちょっと難しいようです。
whileかなんかを使って、うまく工夫することはできるので
しうか?
私もちょっと考えてみます?

Weasel 2000/03/12(日) 19:38:36
S-poreさんの教わった方法を自分なりにアレンジ
してみました。

> open(OUT, "data.csv");
> while ($csv_line = reverse(<OUT>)) {
> @data_view = split(/,/,$csv_line);
> print "<tr>";
> print"<td bgcolor=\"#ffffdd\">$data_view[0]<\/td>";
> print"<td bgcolor=\"#ffffdd\">$data_view[1]<\/td>";
> print"<td bgcolor=\"#ffffdd\">$data_view[3]<\/td>";
> print"<td bgcolor=\"#ffffdd\">$data_view[2]<\/td>";
> print"<\/tr><\/table>";
> }
> close(OUT);

なんかサーバー処理にすごい時間がかかるように
なってしまいました。1分以上かかってもページが表示されない
です。S-poreさんのスクリプトをそのまま貼り付けた場合では
ページなんか3秒くらいで表示されたのに、?

これって、「巨大な場合」だからでしょうか?

S-pore [HomePage] 2000/03/12(日) 20:12:30
> 現在、データファイルは6,311バイトです。多くても10Kを超す
> ことはないと思いますが、どのくらいが「巨大な場合」に
> なるのでしょうか?

10KB以内なら私の感覚的にはまったく問題ないです。
サイズがMB単位の場合は別の方法でやらないとスラッシング地獄に陥ったりします。(←経験者)

> セルごとに色を変えたり、nowrapを
> かけたり、といったことができるのですが、この方法では
> ちょっと難しいようです。

ごめんなさい,書いてあった例が4つとも同じタグ付きだったので,
ここの掲示板の容量節約のために書き方を変えてはしょっちゃったんです。(^^;
じゃあ,普通に書きますね。(最初からこうすればよかったのに←アポ)

open(OUT, "data.csv");
print "<table>\n";
foreach (reverse(<OUT>))
{
  @data_view = split(/,/);
  print "<tr>";
  print "<td bgcolor=\"#ffffdd\">$data_view[0]<\/td>";
  print "<td bgcolor=\"#ffffdd\">$data_view[1]<\/td>";
  print "<td bgcolor=\"#ffffdd\">$data_view[3]<\/td>";
  print "<td bgcolor=\"#ffffdd\">$data_view[2]<\/td>";
  print "</tr>\n";
}
print "</table>\n";
close(OUT);

Weasel 2000/03/12(日) 20:26:52
S-poreさんのコメントと入れ違いになったようです。
コメントありがとうございます。

> ごめんなさい,書いてあった例が4つとも同じタグ付きだったので,
こちらこそすみません。テーブルやフォントの色指定が複雑で、
あまり本題と関係ないと思ったので、削除したのでした。

アドバイス通りにやってみます。
(whileではなくforeachを使うのですね)

Weasel 2000/03/14(火) 23:08:35
[[解決]]
連絡が遅くなりました。
問題なく動作するようになりました。

#しかし、なんでwhileだとページが表示されないのだろう?

Weasel 2000/03/14(火) 23:09:32
S-poreさん、いろいろアドバイスを下さいました
人たちに、心より御礼申し上げます。

mm 2000/03/15(水) 01:29:57
>#しかし、なんでwhileだとページが表示されないのだろう?
while の ()内はスカラコンテキストで、
foreach の ()内はリストコンテキストだから、ということと、
<OUT> のスカラコンテキストとリストコンテキストでの挙動と、
reverse <OUT> のスカラコンテキストとリストコンテキストでの挙動が
異なるためです。
以下の2つのコードを試してみれば分かりやすいと思います。

  open(OUT, "data.csv");
  $s = <OUT>;
  print "$s\n";

  open(OUT, "data.csv");
  $s = reverse <OUT>;
  print "$s\n";

# reverseのスカラコンテキストでの不審な挙動については私も知らなかった…

[上に] [前に] [次に]