• ベストアンサー

ファイル操作について

別スレ立てているので、ルール違反になっちゃいますかね? もしそうであればゴメンナサイ… sub fanc{ my @array = @_; my $ag = shift @array; my $n1 = 'AAA.csv'; my $n2 = 'BBB.csv'; my $n3 = 'CCC.csv'; my $n4 = 'DDD.csv'; my $n5 = 'EEE.csv'; ・ opendir(DIR, "C:/Program Files/Apache Group/Apache2/cgi-bin/test");my @pairs = readdir(DIR); close(DIR); if($ag == 1){@files = grep(/$n1/,@pairs); } if($ag == 2){@files = grep(/$n2/,@pairs); } if($ag == 3){@files = grep(/$n3/,@pairs); } if($ag == 4){@files = grep(/$n4/,@pairs); } if($ag == 5){@files = grep(/$n5/,@pairs); } if($ag == 6){@files = grep(/$n6/,@pairs); } ・ $dfile1 = $files[0]; open(IN,"$dfile1") or exit; chomp(my $row01 = <IN>); chomp(my $row02 = <IN>); chomp(my $row03 = <IN>); chomp(my $row04 = <IN>); chomp(my $row05 = <IN>); chomp(my $row06 = <IN>); ・ close(IN); my @col01 = split(/,/, $row01); my @col02 = split(/,/, $row02); my @col03 = split(/,/, $row03); ・ ・ こういったコードをもっと短く、書くやり方を知りたいです。 grepでヒットするのが複数の場合もあるため、当初はForeach文とフOpenで配列@filesに入った ファイルを全て展開して、配列、又は変数に格納しようと思ったのですが、どうやって複数の配列をOpen関数で扱えばいいのか解りません。 もしそうでなければ、現在は一つのファイルに対しての処理ですが、残ったファイルに関しても関数を回す方法があれば、ご教授願えませんか??あ、あと、CODE(xxxxxx)ってなんのことでしょう?

  • Perl
  • 回答数5
  • ありがとう数2

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

  • ベストアンサー
  • sakusaker7
  • ベストアンサー率62% (800/1280)
回答No.5

> サブルーチンの演算子は何かの布石なのでしょうか? サブルーチンの演算子とは何を指しておっしゃっているのでしょうか? add/subtract等のサブルーチンで使っている+、-等の演算子ということであれば 特に深い意味はありません。 短く書けて分かりやすい例を思いつければよかったんですが。

polalis
質問者

お礼

sakusaker7様、ご回答ありがとうございます。 リファレンス…多少は砕けましたが、やっぱり難しいです。。。 多次元配列に出来るとか、そういう部分での文献を色々読みましたが、自分で使いこなせるように ならないと、多分完全に理解は出来ないですよね。 色々、ご丁寧にありがとうございました。 これから勉強する課題にいたします。

その他の回答 (4)

  • sakusaker7
  • ベストアンサー率62% (800/1280)
回答No.4

> この結果値は、どうやって表示したらいいのですか? 例に出したように、dereferenceしてやればいいです。 ただし相手はサブルーチンなので、引数の数があってないとダメですけど。 そもそも意図しないでリファレンスが返ってくるほうが問題ではないでしょうか? > 通常は、どうやって参照するものなんですか? &$fnc_ref; とか $fnc_ref->(); のようにすると呼び出しになります。 #これは引数がない場合 > なんのために使うのかとか、色々お手数でなければリファレンスについてご教授ください。 サブルーチンへのリファレンスであれば、 Cでいうところの関数ポインタみたいな使い方をします。 あとは多次元配列を実現するためとか、オブジェクトを作るためなんかに リファレンスは使われます。詳しくは perldoc perlref で。 あまりいい例が思い浮かばなかったのですが use strict; use warnings; sub add { my $lhs = shift; my $rhs = shift; $lhs + $rhs; } sub subtract { my $lhs = shift; my $rhs = shift; $lhs - $rhs; } sub multiply { my $lhs = shift; my $rhs = shift; $lhs * $rhs; } sub div { my $lhs = shift; my $rhs = shift; $lhs / $rhs; } sub modulo { my $lhs = shift; my $rhs = shift; $lhs % $rhs; } my @fn_table = (\&add, \&subtract, \&multiply, \&div, \&modulo); my $arg1 = int(rand(100))+1; my $arg2 = int(rand(100))+1; print "arg = $arg1, $arg2: "; foreach my $fnc_ref (@fn_table) { print $fnc_ref->($arg1, $arg2), ", "; #print &$fnc_ref($arg1, $arg2), ", "; }

参考URL:
http://www.kt.rim.or.jp/~kbk/perl5.005/perlref.html
polalis
質問者

補足

sakusaker7様、ご回答ありがとうございます。 文献もバッチリ読みました…が、私にはいまいち理解が苦しいです。 スミマセン…それから上記のコードなのですが、サブルーチンの演算子は何かの布石 なのでしょうか? せっかく教えていただいてるのに、申し訳ないのですが解説も頂けると幸いです。

  • BLUEPIXY
  • ベストアンサー率50% (3003/5914)
回答No.3

#2>@filesをshiftしていって それでもいいですけど、foreach でいいような・ あと、$rownn=<IN> も @rows=<IN> でいいような気がします。 #2>原因は、最終行に"1,3,4"や"1:4"のようなデータが入っているから あれって、"1,3,4"や"1:4"は、調べるべきパターンで、最終行には返すべき結果が、入っているという前提ですよね。 最終行が、そういうパターンの場合もあるなら、 最終行のそういう変換はしないというように変更しないといけないですね。 単純にループでデータの読込&変換をやっていますから、 そのままでは、ループの中で最終行という判断はできませんから、 ループでデータを読み込むのではなくて、 いったん、全部のデータを読み込んでしまってから、 最後のデータ行を除く変換を行うように書き換えればいいと思います。

polalis
質問者

補足

>あと、$rownn=<IN> も @rows=<IN> でいいような気がします。 なるほど…やはり、Foreachの使い方をもう少し勉強しないといけませんね。。。 ここでやりたいことは、ファイルの3列15行の数値データなんですが、 各行の3列目を2列目で割る という処理をしていて、なんとなく最初に配列に入れるより変数から splitして配列に入れたほうが 固体になって計算しやすいかな…と思ったもので。 >ループでデータを読み込むのではなくて は、 open(IN, $dfile) or exit(-1); while(<IN>) { のことですよね?? >単純にループでデータの読込&変換 は、 quotewords("," => 0 , $_); だったり if(index($field, ":") >= 0) { のことでよろしいんですよね? う~ん、やっぱり難しいです。本は結構読んでるですが、なかなか一朝一夕にはいきませんね。。。

  • BLUEPIXY
  • ベストアンサー率50% (3003/5914)
回答No.2

このような場合には、配列やfor で処理することを考えましょう 例えば、 my @n = ('AAA.csv','BBB.csv','CCC.csv','DDD.csv','EEE.csv'); とすれば、 if($ag == 1){@files = grep(/$n1/,@pairs); } if($ag == 2){@files = grep(/$n2/,@pairs); } … は、 @files = grep(/$n[$ag-1]/,@pairs); とできると思います。

polalis
質問者

補足

BLUEPIXY様、お返事遅れました。せっかく教えてくださっているのに、ゴメンサイ… アドバイスありがとうございます。 長々しく書いていた、コードが少しスッキリしました。 Open関数で扱うファイルが複数の場合は、やはり一つ目を読んだ後に@filesをshiftしていって $dfile1 = $files[0];をif文等でデータ無しまで、評価すればいいですよね? ところでBLUEPIXY様に直接お聞きしたかったのですが、以前教えて頂いた、絞り込む関数(squeezed) で質問なのですが、 >CODE(xxxxxx)ってなんのことでしょう? は、このサブルーチンの戻り値で出てしまうものなんです。 原因は、最終行に"1,3,4"や"1:4"のようなデータが入っているからだと思うんですが この値を、どうにか返せないものでしょうか? CODE(xxxxxx)は、どうやって参照すればいいのですか?? 本当に何度もお手数をおかけして、申し訳ありませんがご教授下さい。

  • sakusaker7
  • ベストアンサー率62% (800/1280)
回答No.1

とりあえず > CODE(xxxxxx)ってなんのことでしょう? についてだけ。 コードのリファレンスを普通の変数のように表示しようとすると出る奴ですね。 $code_ref = sub { print "hello, world\n"}; print $code_ref; print "\n"; &$code_ref; 実行結果: CODE(0x1626160) hello, world

polalis
質問者

補足

sakusaker7様、遅くなりましてゴメンナサイ。 回答ありがとうございます。 なるほど、コードのリファレンスを普通に見ようとすると出るもの なんですか。。。 #2のBLUEPIXY様にも、お尋ねしてしまっているのですが、この結果値は、どうやって表示 したらいいのですか? 通常は、どうやって参照するものなんですか? 当方Perl初心者の為、いまいちリファレンスの感じがつかめません。 なんのために使うのかとか、色々お手数でなければリファレンスについてご教授ください。

関連するQ&A

  • 集計プログラム

    sub fanc{ my $dir = "ディレクトリ";my @array = @_; my $n = $array[0];my $id = $array[1]; my @csv1 = ('AAA.csv','BBB.csv','CCC.csv','DDD.csv',EEE.csv'); my @csv2 = ('FFF.csv','GGG.csv','HHH.csv','III.csv',JJJ.csv'); my @csv3 = ('KKK.csv','LLL.csv','MMM.csv','NNN.csv','OOO.csv'); opendir(DIR, $dir) or exit; @pairs = grep { -f "$dir/$_" ? $_ : '' } readdir(DIR); close(DIR); if($id == 1){ $pattern = $csv1[$n -1]; } elsif($id == 2){ $pattern = $csv2[$n -1]; } elsif($id == 3){ $pattern = $csv3[$n -1]; } }else{ undef; } @files = grep(/$pattern/, @pairs); until(@files == 0){ my $data = shift @files; open(IN, $data) or exit; @file = <IN>;chomp @file; close(IN); foreach my $i (@file){ my @m = split(/,/, $i); push my @rec1, $m[1]; push my @rec2, $m[2]; } $val1 += $rec2[0]; shift @rec2; $val2 += $rec2[0]; shift @rec2; $val3 += $rec2[0]; shift @rec2; $val4 += $rec2[0]; shift @rec2; $val5 += $rec2[0]; shift @rec2; $val6 += $rec2[0]; shift @rec2; $val7 += $rec2[0]; shift @rec2; $val8 += $rec2[0]; shift @rec2; $val9 += $rec2[0]; shift @rec2; $val10 += $rec2[0]; shift @rec2; } %tmp; my @rec = grep( !$tmp{$_}++, @rec1 ); foreach my $x (@rec){$sum1 += $x;} $res1 = $val1 / $sum1 * 100; $res2 = $val2 / $sum1 * 100; $res3 = $val3 / $sum1 * 100; ・ ・ こんな感じでパーセンテージを出していますが、csvのデータは全て違うのに、引数を変えて並べて実行すると 答えが同じように返ってきます。どこかおかしいのでしょうか?

    • ベストアンサー
    • Perl
  • 教えてください

    何度もこちらでお世話になっております。どうしてうまくいかないのか、教えて下さい。 下記csvファイルは問題ないのですが、それ以外を引数に与えると結果が表示されません。 概要:アンケート  ≪test.html≫ ※設問ファイル 質問1~5(3択)まである ≪test.cgi≫ ※結果表示 &ReadParseを使用 @pairs = ($in{'q1'},$in{'q2'},$in{'q3'},$in{'q4'},$in{'q5'}); $values = Gettest("data1.csv",@pairs); print $values,"\n"; ≪test.pl≫ ※サブルーチン sub Gettest { use Text::ParseWords;  #// 標準モジュール my @array = @_; my $dfile = shift @array; #// CSVファイル @data = (); #// 配列の初期化(読み込んだデータの格納用) open(IN, "$dfile") or exit; #// データファイルの読込み while(<IN>) { chomp; @fields = quotewords("," => 0 , $_); #// カンマ区切りデータの取り込み foreach $field (@fields){ if(index($field, ":") >= 0) { $field =~ s/:/-/; #// データの整形(1:3→[1-3]) $field = "[$field]"; } elsif(index($field, ",") >= 0) { $field =~ s/,/\|/g;#// データの整形(1,3,4→1|3|4) }} push @data, [@fields]; } close(IN); $rows = @data; $cols = @{$data[0]}; $values = squeezed(@array);#// 該当範囲の絞り込み return "$values\n"; exit; sub squeezed { my @para = @_; my @pos = (0 .. ($cols -1)); my $i, @wk; for($i = 0; $i < $rows -1; $i++) { @wk = (); foreach my $p (@pos) {#// 有効な位置だけ調べる if($para[$i] =~ /$data[$i]->[$p]/) { push @wk, $p; #// パターンマッチする位置を配列に保存 }} @pos = @wk; } if(@pos == 1){ #// 結果算出 return $data[-1]->[$pos[0]]; } else {return exit;#// 結果が該当なし、もしくは2個以上ならエラーを返却 }}} 1;

    • ベストアンサー
    • Perl
  • サブルーチンの結果

    my @data; my ($rows,$cols); sub Gettest { use Text::ParseWords; my $dfile = shift; # CSVファイル my @array = @_; @data = (); open(IN, $dfile) or exit(-1);# while(<IN>) { chomp; my @fields = quotewords("," => 0 , $_); # カンマデータの取込 foreach my $field (@fields){ if(index($field, ":") >= 0) { my @range = split(':',$field);# 範囲の取出し $field = sub { my $v = shift; return $range[0] <= $v && $v <= $range[1];}; } elsif(index($field, ",") >= 0) { my @list = split(',',$field); #種類の取出し $field = sub { my $v = shift; return grep($v == $_, @list); };}} push @data, [@fields];} close(IN); $rows = @data; $cols = @{$data[0]}; return squeezed(@array);#// 該当範囲の絞り込み} sub squeezed { my @para = @_; my @pos = (0 .. ($cols -1)); my $i; my @wk; for($i = 0; $i < $rows -1; $i++) { @wk = (); foreach my $p (@pos) {# 有効な位置 my $test = $data[$i]->[$p]; if("CODE" eq ref($test)){ # 範囲テストコードの場合 push @wk, $p if &$test($para[$i]); # test がOK } elsif($para[$i] eq /$test/) {push @wk, $p; # マッチ位置を配列に}} @pos = @wk;} if(@pos == 1){ return $data[-1]->[$pos[0]]; } else {return undef;#// 該当なしか2個以上ならundefを返却 }}1; 引数によってCSVデータの範囲を絞って結果を返すといった関数を、ご提供して頂いた のですが、「1:4」や「1,3,4」等の答えがCODE(XXX)になってしまいます。ご提供者様から、ループで変換するのではなく 最終行のみ変更を加えないようにするというアドバイスを頂いて色々ためしてみたのですが、 私のレベルではサブルーチンの理解が出来なくて全然うまくいきません。他力本願な お願いで申し訳ないのですが、解る方教えて下さい。

    • ベストアンサー
    • Perl
  • 動的CSVファイルから値なしを削除したい

    jqueryについて質問です。とある動的csvファイルからある特定の列を取り出し、grepを使って値のないものを取り除きたいと思っています。しかしunderfindとなってしまいます。どこを修正すればいいのでしょうか? ちなみにgrepのところを削除すると、「90 247 312 149 360 NaN 110 yMin=90, yMax=360 」という値が返ってきます。 希望は「90 247 312 149 360 110 yMin=90, yMax=360 」という値が返ってきて、最終的には最終行から3つの値、「149 360 110」を取り出したいと考えております。 このcsvファイルは動的で、行数は変化します。 function loadcsv2(url) { if (window.ActiveXObject) { var httpObj = new ActiveXObject("Microsoft.XMLHTTP"); if (httpObj) { httpObj.open("GET","sample2.csv", false); httpObj.send(); } } else if (window.XMLHttpRequest) { httpObj = new XMLHttpRequest(); httpObj.open("GET", "sample2.csv", false); httpObj.send(null); } var rows = httpObj.responseText.split("\r\n"); var dates = new Array(); var items = new Array(); items[0] = new Array(); var result = ""; var n; for (n = 1; n < rows.length; n++) { var fields = rows[n].split(","); if (fields.length < 3) break;//3列目まで dates[n] = fields[0]; items[0][n] = n==0 ? fields[1] : parseInt(fields[1]); var datax = items[0][n] datax = $.grep(datax,function(e){ return e;}); result += datax + "\n" ; } } ===【sample.csv】=== day,sizeA,sizeB 11-19,90,254 11-20,247,261 11-21,312,258 11-24,149,250 11-25,360,215 11-26,,450 11-27,110,196

  • grepとsort

    my $files = readdir(DIR); @files = grep { !/^\.\.?$/; } @files; 「.」と「..」の除去 @files = sort { $a cmp $b; } @files; ファイル名のソート この2文についてですが、grepとsortに関する文法がよくわかりません。 grepって、除去するコマンドなんでしょうか? sortでは、$a cmp $bが何を意味しているのでしょうか。

    • ベストアンサー
    • Perl
  • ファイルの書き込み2

    またまた失礼します。 やりたいことは以下です。 1.ディレクトリを開く。 2.ファイル達を読み込み。 3.追記用のデータファイルを開く。 4.「2」にデータを追記 5.別のディレクトリに書き出し。 以上です。 4番がうまくいきません。 ためしに4の工程を抜かすと問題なく書き出されます。 4の工程でやりたいことは、 1.タブ区切りのテキストファイルを読み込み。 2.書き出し用に読み込んだ(追記したいファイル)<productのpath="[ココの値!]"を取得。 3.「2」番で取得した値と「1」番で取得した値を比較。 4.「3」がtrueの行を追記して書き出し。 以上。 要するになにがしたいかというと、 仮にタブ区切りテキストには10行分のデータがあるとします。 それぞれの行には3つ分の値が入っており、先頭にIDが付いています。 一番最初に読み込んだファイル(追記したいファイル)にも同様にIDが振られており(<product path="ココ")そのIDとタブ区切りテキストのIDが一致した行だけ追記したいということです。 下記のコードだとなぜか、 10行分のデータがすべて追記されてしまいます。 コードは以下です。 #!/usr/bin/perl #既存ファイル読み込み&追記 $n_dir = "newXml/"; $b_dir = "xml/"; opendir(DIR, $b_dir); while($file = readdir(DIR)){ $bfile="$b_dir$file"; $nfile="$n_dir$file"; $dfile="data/data.txt"; if (-T $bfile) { open(IN, $bfile);#既存ファイルオープン @list = <IN>; close(IN); open(OUT,">$nfile");#書き出しファイルオープン foreach $line (@list) { if ($line =~ /\<product/){ $line =~ /path=\".*\"/;#path取得 $1; } if ($line =~ /\<\/product\>/) { open(IN, $dfile);#追加データファイルオープン while($data = <IN>){ chomp(@data = split(/\t/,$data)); $data[0] =~ s/\//_/g; if($data[0] == $1){#取得したパスとdata.txtとってきた値を比較 print OUT <<EOF; <ds path="$data[0]">$data[1]</ds> <kw>$data[2]</kw> $line EOF } else{next;} } close(IN) }else{print OUT $line;} } close(OUT); } else{next;} } closedir(DIR); 長々と申し訳ありません。 エラーなどは特にありません。 ご協力お願いします。

    • ベストアンサー
    • Perl
  • perl ディレクトリ ツリー表示

    下記ソースコードでカレントディレクトリのツリー表示ができますが、これを特定のディレクトリ内をツリー表示できるようにする方法がわかりません。 opendir関数の$dirの前にtestをつけましたが、うまく行きません。 特定のディレクトリは任意で変えることができることとします。 sub treelist_ { my ($dir, $lv) = @_; opendir my $dh, $dir; my @files = grep { $_ !~ /^\.\.?$/; } readdir $dh; closedir $dh; for my $file (@files) { print ">" x $lv, "$dir/$file\n"; treelist_("$dir/$file", $lv+1) if -d "$dir/$file"; } } sub tree { for my $dir (@_) { print "$dir\n"; treelist_($dir, 0); } } tree('.');

  • ディレクトリ全てのファイルを読み取るには?

    フリーのCGI掲示板を使ってます。ディレクトリ内に複数のログファイルがあるので、一括して編集・削除ができるように管理部分を改造したいのでアドバイスをお願いします。 一応、readdir関数でディレクトリ内にある全てのファイル名を取得でることは分かりましたが、open関数で全てのファイルを読み取らせる方法がわかりません。 open DIR "./log"; @files = readdir DIR; close DIR; #以下、オリジナルのソースです。 open(IN,"$logfile") || &error("Open Error: $logfile"); while (<IN>) { my ($no,$dat,$nam,$eml,$sub,$com,$url,$hos) = split(/<>/); #途中略 } close(IN);

    • ベストアンサー
    • Perl
  • ファイル名を一括変更したいが正規表現方法を教ええください。

    リモート側のファイル名を一括変更したのですが、正規表現の方法がわかりません。 現在は以下のとおり記述しています。 opendir(DIR, $FTPdir); @FTPlist = grep (/^$head$year$mon$mday.*\.csv$/, readdir(DIR)); closedir(DIR); if (@FTPlist){ foreach (@FTPlist) { rename /^$head$year$mon$mday.*\.csv$/,/^$head$year$mon$xday.*\.csv$/,); print ; print "\n"; } }

    • ベストアンサー
    • Perl
  • 意味の説明

    VBAだと思うのですが 次はそのプログラムの意味で,with以下のコードの意味がどういうことを意味しているか、全くわからないので解釈していただけませんか。 私はVBAはしろうとです。 If i = 0 Then MsgBox MY_FOLDER & " には、CSVファイルが存在しません。", vbCritical: Exit Sub   Application.ScreenUpdating = False   Application.DisplayAlerts = False   For Each n In myCSVFnames    xlFileName = Mid$(n, 1, InStrRev(n, ".csv")) & ".xls"    If Dir(MY_FOLDER & "\" & xlFileName) = "" Then      With Workbooks.Open(MY_FOLDER & "\" & n, Format:=2)       .SaveAs MY_FOLDER & xlFileName       Workbooks(xlFileName).Close False       j = j + 1      End With    End If   Next n

専門家に質問してみよう