- ベストアンサー
ファイルの書き込み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); 長々と申し訳ありません。 エラーなどは特にありません。 ご協力お願いします。
- みんなの回答 (3)
- 専門家の回答
質問者が選んだベストアンサー
またまた失礼。。 $data[0] と $1 の中身が空でないかチェックしても駄目ですか? if($data[0] ne ""){~ >if($data[0] == $1){#取得したパスとdata.txtとってきた値を比較 の==をeqに変えてみても駄目ですか? (==は、数値でない場合や文字列として認識されてしまった数字の場合、正しく比較できないことがあります。 経験上、eqなら間違いなく比較してくれます) ご質問の件とはまったく無関係ですが、 >open(IN, $dfile);#追加データファイルオープン から >close(IN); までの間に処理をたくさん行なうと、その隙に外部からファイルアクセスがあったときに、ファイルを破壊されることがあります。 あらかじめ書き出す変数や配列を用意しておき、openからcloseまでを最短にするようにした方が安全ですよ。 前回私が書いたスクリプトが見本です。(恥)
その他の回答 (2)
- sakusaker7
- ベストアンサー率62% (800/1280)
たぶん if ($line =~ /\<product/){ $line =~ /path=\".*\"/;#path取得 $1; } ここで$1に何か入っていると思っていて、さらに if($data[0] == $1){#取得したパスとdata.txtとってきた値を比較 ここでそれを参照しているつもりなんだろうけど、それじゃだめです。 まず$1とか$2とかで取り出すには、 $line =~ /path=(".*")/; のように、キャプチャのためのカッコを書かないといけません。 つぎに、仮にここでキャプチャしていたとしても if ($line =~ /\<\/product\>/) { こことか $data[0] =~ s/\//_/g; ここで正規表現を使った操作をしてしまっているから、ぶっ壊されます。 $<*digits*> Contains the subpattern from the corresponding set of capturing parentheses from the last pattern match, not counting patterns matched in nested blocks that have been exited already. (Mnemonic: like \digits.) These variables are all read-only and dynamically scoped to the current BLOCK. データファイルの読み込みは一回だけやれば十分だと思うけど もう寝るので指摘だけ :)
お礼
できました!!!! $line =~ /path="(.[^\"]*)"/;#path取得 $id = $1; ~~略~~ if($data[0] eq $id){#取得したパスとdata.txtとってきた値を比較 こうしたらちゃんと比較されました! ありがとうございます!
- Ceren
- ベストアンサー率49% (90/183)
> 4.「2」にデータを追記 > 4番がうまくいきません。 「追加データファイルオープン」のところで「>>」の指定がないので 期待通りに動かないのではないですか?
補足
ご回答ありがとうございます。 追記モードにするということでしょうか。 試してみましたけど変わりありませんでした。
お礼
またまたありがとうございます!! 空のチェックをしたら$1に値が入ってなかったです。 ただ、=をeqに変えたらちゃんとでなくなりました! つまり$1に値が入っていないので当然falseなので、 値が出ないという正しい処理になりました。 あとは$1にデータさえ入れば・・・ >までの間に処理をたくさん行なうと、その隙に外部からファイルアクセスがあったときに、ファイルを破壊されることがあります。 わざわざご指摘ありがとうございます! とても参考になりました!!!