ようこそ ゲスト さん、新規登録(無料)して気になる疑問を解決しませんか?

質問

質問者:trfnc223 ファイルの書き込み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);

長々と申し訳ありません。
エラーなどは特にありません。
ご協力お願いします。
質問投稿日時:08/03/11 18:43
質問番号:3853704
この質問に対する回答は締め切られました。
最新から表示回答順に表示良回答のみ表示

回答

良回答10pt

回答者:sakusaker7 たぶん
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.

データファイルの読み込みは一回だけやれば十分だと思うけど
もう寝るので指摘だけ :)
種類:回答
どんな人:経験者
自信:参考意見
回答日時:08/03/12 02:33
回答番号:No.3
この回答へのお礼できました!!!!

$line =~ /path="(.[^\"]*)"/;#path取得
$id = $1;
〜〜略〜〜
if($data[0] eq $id){#取得したパスとdata.txtとってきた値を比較

こうしたらちゃんと比較されました!

ありがとうございます!

回答

良回答20pt

回答者:menu_selec またまた失礼。。

$data[0] と $1 の中身が空でないかチェックしても駄目ですか?
if($data[0] ne ""){〜

>if($data[0] == $1){#取得したパスとdata.txtとってきた値を比較
の==をeqに変えてみても駄目ですか?
(==は、数値でない場合や文字列として認識されてしまった数字の場合、正しく比較できないことがあります。
 経験上、eqなら間違いなく比較してくれます)

ご質問の件とはまったく無関係ですが、
>open(IN, $dfile);#追加データファイルオープン
から
>close(IN);
までの間に処理をたくさん行なうと、その隙に外部からファイルアクセスがあったときに、ファイルを破壊されることがあります。
あらかじめ書き出す変数や配列を用意しておき、openからcloseまでを最短にするようにした方が安全ですよ。
前回私が書いたスクリプトが見本です。(恥)
種類:アドバイス
どんな人:専門家
自信:参考意見
回答日時:08/03/12 01:01
回答番号:No.2
この回答へのお礼またまたありがとうございます!!
空のチェックをしたら$1に値が入ってなかったです。
ただ、=をeqに変えたらちゃんとでなくなりました!
つまり$1に値が入っていないので当然falseなので、
値が出ないという正しい処理になりました。
あとは$1にデータさえ入れば・・・

>までの間に処理をたくさん行なうと、その隙に外部からファイルアクセスがあったときに、ファイルを破壊されることがあります。
わざわざご指摘ありがとうございます!
とても参考になりました!!!

回答

 

回答者:Ceren > 4.「2」にデータを追記
> 4番がうまくいきません。

「追加データファイルオープン」のところで「>>」の指定がないので
期待通りに動かないのではないですか?
種類:アドバイス
どんな人:一般人
自信:参考意見
回答日時:08/03/11 18:56
回答番号:No.1
この回答への補足ご回答ありがとうございます。
追記モードにするということでしょうか。
試してみましたけど変わりありませんでした。
この回答へのお礼この回答にお礼をつける(質問者のみ)
 
最新から表示回答順に表示良回答のみ表示