受信データを分割する方法

このQ&Aのポイント
  • 質問文章では、受信データを & で分割し、さらに = で分割していますが、自分でコードを書きたくて、1行ずつ試してみました。
  • ログファイルを開き、データを取得し、分割する方法がわからず苦戦しています。
  • コードを書いてみましたが、うまくいかないようです。どのようにすれば受信データを正しく分割できるでしょうか?
回答を見る
  • ベストアンサー

受信データの分割

@atai = split(/&/,$buffer); foreach $atais(@atai){ ($key, $value) = split(/=/, $atais); $FORM{$key}=$value; } 多分上記のようなことをすればできるのだと思うのですが、 自分の力でコードをかきたくて、1行ずつかいてみました。 #ファイルオープン open FILE,"<log.log"; flock(FILE,2); @log_data=<FILE>; flock(FILE,8); close FILE; foreach(@log_data){ (@log) = split(/=/,$_); } foreach(@log){ ($log_data) = split(/&/,$_); } foreach($log_data){ ($key,$value) = split(/=/,$_); } $FORM{$key}=$value; このようにかいてみたのですがうまくいきません。 よろしくお願いします。

  • CGI
  • 回答数7
  • ありがとう数9

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

  • ベストアンサー
noname#25358
noname#25358
回答No.7

 これはプログラムの基礎の本を読めば書いてあることではありますが……すべてのプログラムは、上から順に処理されていきます。  たとえば、ラーメンを作ろうと思った場合、まずお湯を沸かしてから、カップの中にお湯をそそながければいけません。  お湯を沸かす前の水をカップの中に入れても何にもならないわけです。  それと同じように、$i = 1 という代入は、$i が必要になる以前に代入されていなければいけません。

KODAMAR
質問者

お礼

できました! $iの位置が違うなんて思いもしませんでした。 お手数おかけしてすいませんでした。 まだまだ初心者でわからないことだらけでおかしなことを多々言ってしまったと思います。 今後もまた何かありましたらよろしくお願いします。 本当に本当にありがとうございました。

その他の回答 (6)

noname#25358
noname#25358
回答No.6

 そのソースだと $i に値がなにも代入されていません(^_^;  $ARGV[0] の値を代入するなりなんなりして、$i に値を入れる必要があります。

KODAMAR
質問者

お礼

すいません、1行抜けてました。 #ファイルオープン open FILE,"<log.log"; flock(FILE,2); @log_data=<FILE>; flock(FILE,8); close FILE; @log = split(/&/,$log_data[$i]); foreach(@log){ ($key,$value) = split(/=/,$_); $FORM{$key} = $value; } $i=1; print "Content-type:text/html\n\n"; ってなってます。 print "@log_data<BR><HR>\n"; print "$log_data[$i]\n"; print "MESSAGEは:$FORM{'MESSAGE'}<BR>\n"; 1つ目はログファイル全部。 2つ目はログファイルの中の2番目。 3つ目は一番最初のログファイルのデータのMESSAGE=の後。 というように出てきます。

noname#25358
noname#25358
回答No.5

 最初の foreach は削除されてないのでしょうか?  改行されていれば、行末に = を入れる必要はないので、最初の foreach の3行は削除していいのです。  このとき、行末の = は手で取り除いてください。

KODAMAR
質問者

お礼

回答ありがとうございます。 最初の3行は消したつもりです。 今はこんな状態です。 #!C:\Perl/bin/perl #ファイルオープン open FILE,"<log.log"; flock(FILE,2); @log_data=<FILE>; flock(FILE,8); close FILE; @log = split(/&/,$log_data[$i]); foreach(@log){ ($key,$value) = split(/=/,$_); $FORM{$key} = $value; } print "Content-type:text/html\n\n"; 確かに最後の=は残ってるみたいです。 (別にかまいません。)

noname#25358
noname#25358
回答No.4

 現在のロジックで、すでに $FORM{'NO'} に値が入っていると思うんですが、入ってないのでしょうか?  ちなみに、{'NO'} の部分は全角半角の区別が必要です。

KODAMAR
質問者

お礼

回答ありがとうございます。 @log = split(/&/,$log_data[$i]); foreach(@log){ ($key,$value) = split(/=/,$_); $FORM{$key} = $value; } 上記のようにして、 $FORM{'NO'} とすると ログの1番最初(1番古い)しか出てきません。 これを任意のものにしたいのです。

noname#25358
noname#25358
回答No.3

 最初のお礼のところに書いたとおり、   foreach(@log_data){     (@log) = split(/&/,$_);   }  このロジックでは、@log_data の内容を1行1行処理し、処理した結果をすべて @log に代入してしまいます。  @log は新しい情報が来ると古いものは上書きされてしまうので、結果として最後の行のデータしか残りません。  これを防ぐには、引数として数字を渡してやり、指定された行に対して上記の処理をするようにします。  このプログラムをコマンドラインから実行しているなら、スクリプトファイル名に続けて記述した引数が $ARGV[0] という変数に格納されます。  よって、$log_data[$ARGV[0]] という変数が、任意の行のデータということになります。  上記の3行を削除し、   @log = split(/&/,$log_data[$ARGV[0]]);  と書き換えると、コマンドライン引数の値によって処理される値が変化します。

KODAMAR
質問者

お礼

回答ありがとうございます。 foreach(@log_data){ (@log) = split(/&/,$_); } ↓↓↓↓↓ @log = split(/&/,$log_data[$i]); のようにしてみたところきちんと任意の行が抽出できました。 ありがとうございます。 $FORM{'NO'}のようにして中身を出したいときも上記のようにするのでしょうか? 今は foreach(@log){ ($key,$value) = split(/=/,$_); $FORM{$key} = $value; } となっていますが @logを$log[$i]のように変更するのですか? 上記のように変更してもダメだったのですが…。 何度もすいませんがよろしくお願いします。

noname#25358
noname#25358
回答No.2

 まず、このロジックでは各行の終わりを自分で判定する必要はありません。  @log_data という配列変数に、各行のデータが最初から配列データとして入ってきます。  それから、最後の $FORM{} への代入は、foreach の内側にある必要があります。  これらのことを踏まえ、もう1度作ってみて下さい。

KODAMAR
質問者

お礼

回答ありがとうございます。 こんな感じにしてみました。 foreach(@log_data){ (@log) = split(/&/,$_); } foreach(@log){ ($key,$value) = split(/=/,$_); $FORM{$key} = $value; } 一応 $FORM{'TITLE'} とやると出てくるようになりました。 ありがとうございます。 でも1番新しいログ(ログファイルの一番最後)しか出てきません。 これを任意のものを出すってやるためにはどのようにしたらよいのでしょうか?

noname#25358
noname#25358
回答No.1

 プログラミングは初めてですね?  まず、最初の foreach で、/=/ の中のイコールが全角になっているのはわざとでしょうか?  それから1つ目と2つ目の foreach は、split の出力先がそれぞれ @log、$log_data になっているため、すべての行のデータがこれら1つの変数に出力されてしまいます。  まず、最初の行のデータを split で分割して @log に出力。  次に、2行目のデータを split で分割して @log に上書き、という動作をしてしまいます。  よって、データの最終行のみが有効になってしまいます。  これを防ぐには、split の結果が配列変数に格納されるようにしなければいけません。  2つ目の foreach は、出力先が ($log_data) のみですので、分割された最初の & よりも前のみが有効になります。  3つ目の foreach は、1つ目の foreach の /=/ が全角と半角の間違いだった場合、1つ目の foreach ですでに /=/ で分解されてしまっているので、3つ目の foreach はまるごと無効になってしまいます。  この説明だけでは分かりづらいと思うので、ナンだったら、具体的に何がやりたいのかを補足してみてください。

KODAMAR
質問者

お礼

回答ありがとうございます。 >まず、最初の foreach で、/=/ の中のイコールが全角になっているのはわざとでしょうか? はい、これはわざとです。 行の1番最後に「=」をつけて行の終わりを認識させているのです。 希望は@log_dataの中身を任意の行数で選択し、その行のデータを $FORM{'NO'} $FORM{'TITLE'} などとして抜き出したいのです。

関連するQ&A

  • ログファイルと受信データを比べたい。

    フォームを使用して送られてきたデータをlogを比べて同じものがあったら、同じものがあるということを表示したいのです。 前にも同じようなことをしてできたはずなのですが、なぜかできなくて…。 もうずーっとやっていて頭がボーッとしてきてしまいました。。。。 #フォームで受信したデータ read(STDIN,$buffer,$ENV{'content_length'}); $buffer =~ s/%([a-fA-F0-9][a-fA-F0-9])/pack("C", hex($1))/eg; #ログファイルオープン open FILE,"naisen.log"; @FILES =<FILE>; close FILE; $i=0; $n=0; $gyou = @FILES; #文末の改行を削除 $buffer =~ s/\n$//; $FILES[$i] =~ s/\n$//; foreach(@FILES){ @log = split(/&/,$FILES[$i]); ($keys,$values) = split(/=/,$log[$_]); $FORMS{$keys} = $values; } for ($i=0; $i<=$gyou-1;$i++){ if ($buffer eq $FILES[$i]){ print "$i行目<BR>\n"; } else{ print "$i行目。これはありません。<BR>\n"; print "$FILES[$i]<BR>\n"; print "$buffer<BR>\n"; } } ログの1行目と同じものとときだけ、きちんとした結果がでます。 上記のほかにもいろいろやりましたができませんでした。

    • ベストアンサー
    • CGI
  • if文中で@***(配列変数)って・・・。

    if文中で配列変数って使用できるのでしょうか? やりたいことは、 フォームを使って入力されたデータと、ログファイルの中身を1行ずつ比べて、 同じものがあったら、そこで比較を終了させる、というようなことをやりたいのです。 たとえでこんな感じでif文つくりました。(これもあってるかどうか微妙なのですが。) for($i=0; $i<5){ @FILELOG2 = split(/&/,$FILELOG[$i]); if (@FILELOG2 eq @log){ print "ok\n"; }else{ print "ng\n"; } exit; } フォームを使って入力されたデータは、 read(STDIN,$buffer,$ENV{'content_length'}); $buffer =~ s/%([a-fA-F0-9][a-fA-F0-9])/pack("C", hex($1))/eg; @log =split(/&/,$buffer); のような感じで処理してあります。 ログファイルは #ログファイルをオープン。 open FILE,"<02.log"; flock(FILE,2); @FILELOG=<FILE>; flock(FILE,8); close FILE; のようにしてあります。 おわかりの方、よろしくお願いします。

    • ベストアンサー
    • CGI
  • TSVデータを上書きしたい

    はじめまして。 CGI初心者です。 データの上書きがしたいのですがなかなかうまくいかなくてこまっています。 以下のソースは追加書き込み処理には成功しています。 以下に何を施せば上書きがうまくいくのかアドバイスをお願いします。 $scheduleFile2 = qq($form{"mon"}.tsv); # 読み込み処理 open(LOG,"$scheduleDir/$scheduleFile2"); @logs = <LOG>; close(LOG); foreach $logs(@logs){ ($golfdate,$areada,$ken,$date2,$para)=split(/\t/,$logs); } # 読み込み処理 # 書き込み処理 unless(&serchFile($scheduleDir,$scheduleFile2)){ &makeFile("$scheduleDir/$scheduleFile2"); } @DATA = (); open(FH,"+<$scheduleDir/$scheduleFile2"); flock(FH,LOCK_EX); while(<FH>){ $_ =~ s/\r//g; $_ =~ s/\n//g; # 行の末を削除する chomp; push(@DATA,$_); } $data01 = $form{"code"}.$form{"date"}; $data2 = $form{"area"}; $data3 = $form{"prefecture"}; $data4 = $form{"date"}; $data5 = $form{"open_state"}."\n"; $data = qq($data01\t$data2\t$data3\t$data4\t$data5); print FH "$data"; flock(FH,8); close(FH);

    • 締切済み
    • CGI
  • 半角スペースが有効にならない。

    前のページで入力された値を取得するCGIですが、どうしても半角スペースを認識しません。 それどころか、半角スペースの後ろを一切消してデータを取得しています。 同じように作成したものはきちんと動いているのに…。 どこが間違ってるかご指摘お願いします。 ---------- #!/usr/local/bin/perl read(STDIN,$buffer,$ENV{'content_length'}); @atai = split(/&/,$buffer); foreach $atais(@atai){ ($key, $value) = split(/=/, $atais); $FORM{$key}=$value; } $buffer =~ s/%([a-fA-F0-9][a-fA-F0-9])/pack("C", hex($1))/eg; $value =~ s/%([a-fA-F0-9][a-fA-F0-9])/pack("C", hex($1))/eg; $key =~ s/%([a-fA-F0-9][a-fA-F0-9])/pack("C", hex($1))/eg; $buffer =~ tr/+/ /; $value =~ tr/+/ /; $key =~ tr/+/ /; print "Content-type:text/html\n\n"; print "$key<BR>\n"; print "<A HREF=./***.cgi>Back</A><BR>\n"; open (FH,">***.log"); @filew="$buffer\n"; print FH @filew; close(FH); exit; ---------- 以上です。よろしくお願いします。

    • ベストアンサー
    • CGI
  • cgiログファイルの書き込みに余計なスペースが入る。

    ---------- #ここでログファイルに書き込みを行う。 open(FH,">>log.log"); print FH"ID=$ID&COUNT=$COUNT\n"; close(FH); #ログファイルをさらに開く。 open FILE, "<log.log"; flock(FILE,2); @log = <FILE>; flock(FILE,8); close FILE; ログファイルを並び替えてその順番で書き込み。 $gyou = @log; @sort=sort{(split(/&/,$b))[1] cmp (split(/&/,$a))[1];} @log; print "<FONT COLOR=RED>@sort</FONT><BR>\n"; open(FILE2, ">log.log"); print FILE2"@sort"; close (FILE2); ---------- というように行っていますが、一番最初のID=01&とかの前に半角スペースが入ります。 下の行に行くほどスペースが増えます。 どこが原因でしょうか?

    • ベストアンサー
    • Perl
  • cgiログファイル分割について。

    ログファイルを開いて変数に代入しています。 $i=0; foreach(@files){ @log = split(/&/,$files[$i]); ($key1,$value1,$key2,$value2,$key3,$value3,$key4,$value4) = split(/=/); : のようにしました。 print "$key2<BR>\n"; などとしても ***&*** と出てしまいます。 その上で&で分割しているのに何故でしょうか?

    • ベストアンサー
    • CGI
  • CSVデータを読み込み、ファイルにカテゴリを分けて書きこむ

    CSVファイル例 01,0101,○○○,○○○□□,010101, 01,0102,○○○,○○○■□,010102, 02,0201,○○○,○○○□□,020101, ・・・・・ というファイルがあったとすると、 1番目の「01」「02」と、分けて別のファイルに保存がしたいです。 書き込み自体は出来るようなのですが、なぜかループが、番号ごとに1回しかされずに、 log/01.cgi 01<>0101<>○○○<>○○○□□<>010101 log/01.cgi 02<>0201<>○○○<>○○○□□<>020101 となってしまい、全ての生成したファイルには1行しか格納されていません。 ちなみに、csvファイルは1万行近くあります。 ソースはこのような感じです。 $log = "△△△.csv"; # ログ名 $lines = file("$log"); foreach ($lines as $l) { $line = explode(",",$l); $push_line = $line[0]."<>".$line[1]."<>".$line[2]."<>".$line[3]."<>".$line[4]."<>\n"; $LOG[$line[0]] .= $push_line; $cate = $line[0].",,".$line[1]; # サブカテゴリ用 $LOG[$cate] .= $push_line; # カテゴリ用ログを保存 } なお、csvファイルは、 01・・・ 02・・・ 01・・・ 03・・・ のようになっているため、全ての行を読み込むことはしていると思います。 しかし、ログファイルにはなぜか1行分しか書き込まれていません。書き込みの文は以下になります。 foreach($LOG as $key => $value){ $explode = explode(",,",$key); if($explode[0]){ $logfile = "./log/".urlencode($explode[0]).".cgi"; } $file = fopen("$logfile", 'w'); flock($file,LOCK_EX); fwrite($file, $value); flock($file,LOCK_UN); fclose($file); 解決法が分かる方、回答のほどよろしくお願いいたします。

    • ベストアンサー
    • PHP
  • Perl BBS 掲示板 改行処理

    改行処理について教えてください。 今まで書き込み処理で unshift @DATA, "$tm,$FORM{'name'},$FORM{'title'},$FORM{'text'}\n"; としていたのですが、これを use CGI; my $form = new CGI; my $NAME = $form->param('name'); my $TITLE = $form->param('title'); my $TEXT = $form->param('text'); unshift(@DATA,"$tm,$NAME,$TITLE,$TEXT\n"); に変更しました。 すると sub loadFormdata が聞かなくなり、 改行処理他が対応しなくなってしまいました、 この場合、 loadFormdataの部分のどこを変えればよいでしょうか? |------書き込み処理------| sub printdata{ use CGI; my $form = new CGI; &loadFormdata(); open(FILE, "<$FILE"); eval{ flock(FILE, 1) }; @DATA = <FILE>; close FILE; my $tm = time; my $NAME = $form->param('name'); my $TITLE = $form->param('title'); my $TEXT = $form->param('text'); unshift(@DATA,"$tm,$NAME,$TITLE,$TEXT\n"); while(@DATA > $MAX) { pop @DATA; } open(FILE, ">$FILE") or die("error :$!"); eval{ flock(FILE, 2) }; print FILE @DATA; close FILE; } |------改行処理他------| sub loadFormdata { my ($query, $pair); if($ENV{'REQUEST_METHOD'} eq 'POST') { read(STDIN, $query, $ENV{'CONTENT_LENGTH'}); } else { $query = $ENV{'QUERY_STRING'}; } foreach $pair (split(/&/, $query)) { my $key = ("$NAME,$TITLE,$TEXT"); my ($key, $value) = split(/=/, $pair); $value =~ tr/+/ /; $value =~ s/%([0-9a-fA-F][0-9a-fA-F])/chr(hex($1))/eg; $value =~ s/&/&amp;/g; $value =~ s/</&lt;/g; $value =~ s/>/&gt;/g; $value =~ s/\x0D\x0A\s*/<br>/g; $value =~ s/\s+/ /; $FORM{$key} = $value; } }

    • ベストアンサー
    • Perl
  • 行頭に変なスペースが…

    入力したデータをログファイルの一番上に入れたいために以下のようにしました。 open(FH2,"***.log"); flock(FH2,2); @files = <FH2>; flock(FH2,8); close FH2; open(FH,">***.log"); @filew = "user=$FORM{'name'}<>TIME=$FORM{'TIME'}\n@files"; print FH @filew; close(FH); こうするとなぜかログファイルの2行目以降の頭にスペースが1文字分入ります。 2個目のログファイルオープンの3行目 print FH @filew; のスペースが原因かと思い、 print FH@filew; としてみましたが、やっぱりスペースが入りました。 このスペースを入らないようにするにはどうしたらいいでしょうか?

    • ベストアンサー
    • Perl
  • 2つのデータを統合を効率よく出来ません

    2つのデータを統合を効率よく出来ません 2つのデータを統合するプログラムをperlで作成しています。 データはテキストでサーバー環境にあります。 クラスデータ 1,1-1,1年 2,1-2,1年 3,1-3,1年 4,2-1,2年 5,2-2,2年 6,3-1,3年 7,3-2,3年 名前データ 1,田中,たなか 2,伊藤,いとう 3,斎藤,さいとう 4,上野,うえの 5,大阪,おおさか 6,福島,ふくしま 7,矢部,やべ 最終データ 1,田中,たなか,1-1,1年 2,伊藤,いとう,1-2,1年 3,斎藤,さいとう,1-3,1年 4,上野,うえの,2-1,2年 5,大阪,おおさか,2-2,2年 6,福島,ふくしま,3-1,3年 7,矢部,やべ,3-2,3年 以下のプログラムで動作させていますが、件数が多くなると非常に非効率となり動作しなくなります。 ※公開用にプログラムを修正しています。おかしい部分があるかもしれません。 (ここから) 略・・・ open(DB10,"<$namefile") || next; flock(DB10, 1); @lines10 = <DB10>; close(DB10); foreach $lines10 (@lines10) { ($seq,$name,$kana,$classnew,$nennew) = split("<>", $lines10); open(DATA,"$classfile")|| die &error(" $classfile を読み込みopen出来ません"); flock(DATA,1); @lines11 = <DATA>; close(DATA); foreach $lines11(@lines11){ ($seq1,$class,$nen) = split("<>", $lines11); $classnew = $class; $nennew = $nen; open(DATA1,"$classfile")|| die &error(" $classfile を読み込みopen出来ません"); flock(DATA1,1); @line21 = <DATA1>; close(DATA1); foreach $line21(@line21){ local(@val) = split("<>", $line21); if($seq1 == $val[0]){ $line21 ="";} push(@new,"$line21"); } push(@new,"$seq1<>$class<>$nen\n"); open(DATA1,">$classfile")|| die &error(" $classfile をwrite出来ません "); flock(DATA1,2); print DATA1 @new; close(DATA1); @new = ""; } @new1 = ""; open(DB12,"<$namefile") || &error("Can't open $namefile"); flock(DB12, 1); @line12 = <DB12>; close(DB12); foreach $line12 (@line12) { local(@val1) = split("<>", $line12); if($seq == "$val1[0]"){ $line12 ="";} push(@new1,"$line12"); } push(@new1,"$seq<>$name<>$kana<>$classnew<>$nennew<>\n"); open(DB12,">$namefile")|| die &error(" $namefile をwrite出来ません "); flock(DB12,2); print DB12 @new1; close(DB12); } } (ここまで) プログラムの流れとしては(私が解釈している)、2つのファイルを1件読み込み更新を最終行へ毎回行っているというものになります。 恐らく、もっと効率の良い方法があるとは思っているのですが、アイデアが浮かばす止まってしまいました。 このプログラムではなく別のものでもOKです。私がこの方法しかしらないのでこの記述をしています。 ファイルの更新系でアドバイスがいただけたらと思い書き込みます。 ご指導よろしくお願いいたします。

    • ベストアンサー
    • Perl

専門家に質問してみよう