• ベストアンサー

もっとスマートに書きたい

テンプレートファイルがあり、そこにデータファイルから読み取ったデータを表示しようと思っています。 表示しようとしているデータは テーブルでセルがいくつかあるものです。 作ってみたのですが、もう少しスマートにかけないでしょうか。 データ: 1 2 3 4 5 テンプレート: <table> <!-- スタートする。カッコ内はセルの個数 --> <!--_START(4)_--> <tr> <td><!--_CONTENTS_--></td> <td><!--_CONTENTS_--></td> <td><!--_CONTENTS_--></td> <td><!--_CONTENTS_--></td> </tr> <!--_END_--> </table> プログラム: # @sample にテンプレートデータ # @data に データが入っています。 $kazu = @data; $flag = 0; foreach (@sample) {  if (/<\!--_START\((\d+)\)_-->/) {   $flag = 1;   $sell = $1;  } elsif (/<\!--_END_-->/) {   $flag = 0;  } elsif ($flag) {   push(@kurikaesi,$_);  } elsif (!$flag and $sell) {   for($i=0;$i<$kazu;$i+=$sell) {    $j = 0;    @a = @kurikaesi;    foreach $kuri (@a) {     if ($kuri =~ /<\!--_CONTENTS_-->/) {      $kuri =~ s/<\!--_CONTENTS_-->/$data[$i+$j]/g;      print $kuri;      $j++;     } else {      print $kuri;     }    }   }   $sell = 0;   print;  } else {   print;  } } 尚、テンプレートファイルの書式はこだわっていませんが、プログラムを分からないデザイナーに通すことを念頭においています。

質問者が選んだベストアンサー

  • ベストアンサー
  • steel_gray
  • ベストアンサー率66% (1052/1578)
回答No.1

パっと見、スマートっぽいけど、効率とかは自信ないです。 前提として2点ばかり仕様変更。 ・テンプレートは配列に格納せずに一つの変数に全体を格納しておく。(→$template) ・開始を示すコメントにセル数は入れない。  単純に <!--_START_--> としておく。 $template =~ s/<!--_START_-->(.*?)<!--_END_-->/&data_replace($1,@sample)/se; # ↑この1行で 以下の関数の呼び出しと置換を行います。 sub data_replace{ my $orginal_temp = shift; my @data = @_; my $result; my $temp = $orginal_temp; foreach $dat(@data){ if($temp !~ /<!--_CONTENTS_-->/) { $result .= $temp; $temp = $orginal_temp; } $temp =~ s/<!--_CONTENTS_-->/$dat/; } $temp =~ s/<!--_CONTENTS_-->//g; $result .= $temp; return $result; }

moon_night
質問者

お礼

ご回答ありがとうございます。 かなりスマートになりました。 やっぱりやり方次第でこのようにできるのですね。 もっと修行が必要だと思いました。

その他の回答 (4)

  • yuuki0229
  • ベストアンサー率70% (33/47)
回答No.5

geオプションと合わせ置換先で配列操作(破壊)を行うとスマートになることがあります。 my $template = join '', @sample; $template =~ s/<!--_CONTENTS_-->/shift @data/ge; START~END間という条件を実現するには#1さんのように 内側の文字列を置換でサブルーチンに渡す方法がシンプルになりそうです。

moon_night
質問者

お礼

アドバイスをありがとうございます。 置換をうまく使えばシンプルにできそうですね。 他の回答者の方の方法も参考にしてもっと修行に励みます。

  • SE-1
  • ベストアンサー率57% (26/45)
回答No.4

# こんなんどうでしょう。 my @data = qw/1 2 3 4 5/; my ($template,$num); open IN, "< template.txt"; { local $/; $template =<IN>; } close IN; $num = $1 if ($template =~/<!--_START\((\d)\)_-->/); $template =~ s/<!--_CONTENTS_-->/$data[$_]/ for (0..$num-1); print "$template\n";

moon_night
質問者

お礼

ご回答ありがとうございます。 残念ですが、テストをしたところ、5番目が出てきませんでした。 どうやらSTART(4)の数字分しか書き出さないようです。 ずいぶんシンプルになったと思ったのですが、ちょっと工夫すれば使えそうではあります。 今後つかえる機会があれば使ってみたいと思います。

回答No.3

<!--_COUTENTS_--> の箇所が順次 @data の内容になればいいだけなら (<!--_START(4)_--> や <!--_END_--> は無視して) こうすればいいと思います。 my $n = 0; for (@sample) { ++$n if (s/<\!--_CONTENTS_-->/$data[$n]/); } 但し @data には丁度ぴったりの要素が入っていないといけませんが。

moon_night
質問者

お礼

ご回答ありがとうございました。 実は書き忘れていましたが、 @dataの内容は増減する可能性があるので、回答いただいたような手は使えないのです。 条件が足らずに申し訳ございませんでした。

  • steel_gray
  • ベストアンサー率66% (1052/1578)
回答No.2

#1です。 テンプレートのミスがあると無限ループに陥る可能性があるので、 sub data_replace の foreachの前あたりに次の1行を足しておいてください。 return 'TEMPLATE ERROR' if($orginal_temp !~ /<!--_CONTENTS_-->/);

関連するQ&A

専門家に質問してみよう