1つだけ過去を変えられるとしたら?

こんばんは。
ファイルを読み込んで、改行だけの行を省いて、上書きしたいのですが
なぜかうまくいきません。
ループ内にある改行の判定をするIF文がいけないと思うのですが…。
教えていただけないでしょうか?


また、シングルクォーテーションダブルっクォーテーションは同じ意味
なのですか?「""」と「''」


作ったプログラムは以下です。

open(OUT,">$ssifile");

#改行のみのデータは除く
@newtbl = ();
foreach $siline ( @slines)
{
if ($slines ne "\n") {
push @newtbl, $siline;
}
}

print OUT @newtbl;
close(OUT);

宜しくお願いいたします。

A 回答 (2件)

if文のところだけ、変数の名前が違うのが原因では?


他では $siline となっているのに、ここだけ $slines ですが・・・

クォートの違いについてですが、文字列を生成するという点では違いはありません。
ただ、文字列中に書かれた変数が、ダブルでは展開されるのに対し、シングルでは展開されません。
また、エスケープ文字も、シングルの方では \' と \\ 以外は無効になります。

例えば、$a = 123; の時、
  print "$a\'\\\nXYZ";
では
123'\
XYZ
と表示されるのに対し、
  print '$a\'\\\nXYZ';
では
$a'\\nXYZ
と表示されます。

# CGI=Perl ではないので、この手の質問は Perl でしましょう。
    • good
    • 0

まず、ダブルクォートとシングルクォートについては、leaz024さんの回答通り、変数展開されるかされないかの違いと、エスケープシーケンス処理(\nなどが展開)されるかされないかの違いがあります。

同じだと思いこんでるといつか痛い目に遭います。変数展開が必要な物はダブルクォートで、必要ない物はシングルクォートで囲むよう癖をつけておくといいでしょう。

また、ダブルクォートやシングルクォート以外に好きな記号を使うこともできます。

下記はダブルクォート""と同じ、変数$textの中身が表示される
print qq{$text}, qq#$text#, qq%$text%, qq|$text|;

下記はシングルクォート''と同じ、$textという文字列が表示される
print q{$text}, q!$text!, q($text), q?$text?;

記号の前にqqをつけるとダブルクォートと同じ、qだとシングルクォートと同じです。
ただし、() [] {} など、かっことして意味のある記号を使う場合、対応するかっこを使う必要があります。また、記号自身を含む場合\でエスケープしてやるのは同じです。

これは使いこなすと便利です。
例えば <img src="$file.gif" alt="a"> という文字列を変数展開ありで、処理したいとします。
ダブルクォートを使うと、
print "<img src=\"$file.gif\" alt=\"a\">";
と、中の"の前に\を付けて全部エスケープしてやらないといけなくて面倒です。一個でもエスケープを忘れると構文エラーになります。
好きな記号を使えることを知っておけば、
print qq|<img src="$file.gif" alt="a">|;
と、スマートに安全に書けます。

で、本題のファイル処理ですが、いろいろ方法はありますが、私が好んで使うのは、下記のような一時ファイルに出力し、renameで上書きするものです。
------------------------------------------------------------------------
my $file = 'test.txt'; # ファイル名
open(IN, "$file") or die $!; # 読み取り用で開く
open(OUT, ">$file.tmp") or die $!; # 一時ファイルを出力用に開く
while (<IN>) { # 1行ずつ処理する
next if /^\n*$/; # 改行だけの行は無視
print OUT $_; # 一時ファイルに出力
}
close(IN);
close(OUT);
rename("$file.tmp", $file) or die $!; # 一時ファイルを元ファイルにリネーム(上書き)
------------------------------------------------------------------------
上記はファイルが大きいときでも1行分しかメモリを消費しないで済みます。

@lines = <IN>; などと、全行読み込んでから処理すると、極端な話、1GBのファイルなら1GBメモリが消費されます。さらに別の配列にコピーなどしてたら2GB。
    • good
    • 0

お探しのQ&Aが見つからない時は、教えて!gooで質問しましょう!


おすすめ情報