いつもお世話になっております.
環境はWindows XP Pro でActiveperlを使っています.
Perlでしたいことは,「指定の行数目から行を抽出する」ことです.
具体的には以下のようにしたいと思っております.
data.txt
A
B
C
D
E
F
line.txt
2
4
6
output.txt
B
D
F
先ほどある方からサンプルソースを教えてもらったのでそれをベースに作ってみましたが,出力のoutput.txtが空のままです.
use strict;
use warnings;
use feature ':5.10';
use IO::File;
open my $file2, '<', 'line.txt' or die "can't open input $!";
chomp(my @subjects = <$file2>);
close $file2;
open my $newfile, '>>', 'data_out.txt' or die "can't open output $!";
open my $file, '<', 'data.txt' or die "can't open input $!";
while (my $line = <$file>) {
chomp $line;
foreach my $line (@line) {
print $line;
if ($. eq $subjects){
say {$newfile} $line;
}
}
}
close $file;
close $newfile;
どこが間違っているのでしょうか.ご指摘ください.よろしくお願いします.
No.1
- 回答日時:
警告メッセージでてませんか?
while (my $line = <$file>) {
chomp $line;
foreach my $line (@line) {
print $line;
if ($. eq $subjects){
・内と外のループで同じ名前の変数($line)を使っている。
・$subjectsという変数を宣言していない
しかし「ある方」はねーだろ
sakusaker7様
名前を出すと良くないかと思いましたのですみませんでした.
とりあえず自分でできました.ありがとうございました.
use strict;
use warnings;
use IO::File;
open my $file2, '<', 'line.txt' or die "can't open input $!";
chomp(my @subjects = <$file2>);
close $file2;
open my $newfile, '>>', 'data_out.txt' or die "can't open output $!";
open my $file, '<', 'data.txt' or die "can't open input $!";
while (my $line = <$file>) {
chomp($line);
foreach my $subjects (@subjects) {
if ($. eq $subjects){
say {$newfile} $line;
}
}
}
close $file;
close $newfile;
No.2
- 回答日時:
「指定の行数目から行を抽出する」って, 意味わかんないよね.
でも, 単に 1つのファイルに出力するだけならプログラム内で出力ファイルを書くよりも外でリダイレクトさせた方が柔軟だろうとか, 5.10 ならスマートマッチ使えばいいのにとかは思う.
意味が分かりづらくてすみません.Tacosan様には以前もお世話になりました.「指定の行数目から行を抽出する」とはline.txtにある数字(2や4)を利用して,data.txtの行(line.txtにある数字)を抽出するという意味です.実は,16000ほどファイルがあるので,リダイレクション機能は使えないのです.
No.3
- 回答日時:
foreach my $subjects (@subjects) {
if ($. eq $subjects){
say {$newfile} $line;
}
}
の部分は全部まとめて
say {$newfile} $line if grep { $. == $_ } @subjects;
にできると思うし, さらに say を使ってるからには 5.10 だと思うので
say {$newfile} $line if $. ~~ @subjects;
までできないかな? あ, 今は数値として比較してるので, if の条件は eq より == の方が適切ではないでしょうか.
でも, 「リダイレクトが使えない」ってどういうことなんだろう?
なるほど,短くできるんですね.処理速度は向上しますか.
そうですね,==の方が適切ですね.以前"=="で失敗したのでeqにずっとしていました.
リダイレクション機能は1対1だと,perl syori.pl > output.txt などのようにできることは知っているのですが,これは大量の処理を目的に作ろうとおもっているので考えていませんでした.
No.4
- 回答日時:
別に名前を出せという意味でもなくて、単に「別の質問で教えてもらった」
でいいんじゃなかろうかということです。
んで、line.txtに抜き出したい行の行番号があるということであれば
#!/usr/bin/perl
use strict;
use warnings;
use feature ':5.10';
open my $line_file, '<', 'line.txt' or die $!;
my @lines = map { chomp; $_-1} <$line_file>;
close $line_file;
open my $data_file, '<', 'data.txt' or die $!;
my @data = (<$data_file>)[@lines];
close $data_file;
say @data;
とか。
考え方を示すためだけのものなので、いろいろと手を抜いています。
最初の質問で内容の丸呑みしようとしてたのだから、ここで例に出しても
問題ないと考えました。
sakusaker7様
ご回答ありがとうございます.
なるほど,mapを使うとさらに簡潔にできるんですね.勉強になります.
そこで,本題であるディレクトリ内のテキストファイルへの処理なのですが,私はずっと以下の方法で処理してきたため,今回の方法をどう適用したらよいのか分かりません.教えていただけないでしょうか.
my $dirname = '.';
opendir(DIR, $dirname) or die "$dirname: $!";
while (my $dir = readdir(DIR)) {
next unless (-f $dir);
next unless ($dir =~ /\.txt$/);
open(FILE, $dir) or die "$dir: $!";
my @file = <FILE>;
close(FILE);
foreach my $line (@file) {
処理
open(NEWFILE, "> $dir") or die "$dir: $!";
print NEWFILE @file;
close(NEWFILE);
}
No.5
- 回答日時:
ディレクトリ内の各テキストファイルに対して処理するのはいいんですけど, 出力はどうしますか?
・各ファイルごとに (それなりなファイル名の) ファイルに出力する
・全てのファイルに対する出力を全部まとめて 1つにする
どっちにします?
この回答への補足
Tacosan様
ご連絡ありがとうございます.
・各ファイルごとに (それなりなファイル名の) ファイルに出力する
にしたいと思っております.
毎度ながらTacosan様にはご返答いただき,感謝致しております.
No.6
- 回答日時:
OK. あと問題になるのは, ここで出てくる「2個の入力ファイル」の関係.
つまり, 入力ファイルとして data.txt と line.txt がある. data.txt の方は可変だからさておいて, line.txt はどうなんでしょうか? これも, 状況によって
・全てのデータファイルで共通
・各データファイルごとにすべて別々
・(データファイルがサブディレクトリに入っている場合には) 各サブディレクトリごとで共通
など, いろんな場合が考えられます.
と一応書いておくけど, 現状からいちばん簡単に対処するなら, まず「1つのファイルを処理して 1つのファイルに出力する」ところ (つまり「今できている」ところ) を「3個のファイル名を引数に持つ」サブルーチンにします.
で, 各入力ファイルに対し以下のループを回せばいいはず:
・入力ファイルの名前から出力ファイルの名前を作る (必要なら行番号の書かれたファイルの名前も作る).
・先に作ったサブルーチンを適切な引数で呼び出す.
入力ファイルの名前をどのように取り出すかについては, ファイルシステムにおいてどのように配置されているかに依存します.
この回答への補足
Tacosan様
いつもお世話になっております.
入力ファイルのline.txtは「全てのデータファイルで共通」です.
なるほど,
1つのファイルを処理して 1つのファイルに出力する」ところ (つまり「今できている」ところ) を「3個のファイル名を引数に持つ」サブルーチンにします.
で, 各入力ファイルに対し以下のループを回せばいいはず:
・入力ファイルの名前から出力ファイルの名前を作る (必要なら行番号の書かれたファイルの名前も作る).
・先に作ったサブルーチンを適切な引数で呼び出す.
入力ファイルの名前をどのように取り出すかについては, ファイルシステムにおいてどのように配置されているかに依存します.
以上の件了解しました.
まずは自分でやってみます....できなければ申し訳ありませんがお助けいただくかもしれません.
なお,入力するファイルは2000-01-01_00.txtから2000-12-31-23.txtまであります.
ここ2日間粘ってみましたがどうもうまくいきません.ソースが以下です.
入力ファイル(2000-01-01_00.txtから2000-12-31-23.txtまで)をfor文で作成し,
use warnings;
use IO::File;
@dd_max = ( 31,29,31,30,31,30,31,31,30,31,30,31 );
for ($mm=1;$mm<13;$mm++){
for($dd=1;$dd<$dd_max[$mm-1];$dd+1){
for($hh=0;$hh<24;$hh++){
$filename = sprintf("2000-%2.2d-%2.2d_%2.2d.txt",$mm,$dd,$hh);
open(IN,$filename);
open my $file, '<', 'line.txt' or die "can't open input $!";
chomp(my @subjects = <$file>);
close $file;
open my $newfile, '>>', "./out/$filename" or die "can't open output $!";
while (my $line = <IN>) {
chomp($line);
foreach my $subjects (@subjects) {
if ($. == $subjects){
処理
say {$newfile} $line;
}
}
}
close $file;
close $newfile;
}
}
}
close(IN);
エラーとして,
readline() on closed filehandle IN at line.pl line 19
がでます.
ちなみに19行目は while (my $line = <IN>) { です.
いろいろ試してみましたが成功しません.修正点をどなたかご指摘ください.
No.7
- 回答日時:
気になったこと:
・$dd に対するループはおかしいですね. このままだと無限ループ.
・$file に対する close が 2回入ってますな.
・ファイルハンドル IN に対する open/close のタイミングがなんかおかしい.
そのエラーそのものがどこで出てるかはちょっとわかりませんが, 当該ファイルが存在するかどうかは確認した方がいいのでは?
実際の処理の部分はサブルーチンにした方がわかりやすいような気がしますが, そこはまあ趣味なので.
Tacosan様
いつもご回答ありがとうございます.
サブルーチンで作りたかったのですが,ファイルを読み込んで,サブルーチンにもっていくまでが分からなくてこのような形になりました.
それでもだめでしたね.
雰囲気だけでも良いので全体的な流れを書いてもらえないでしょうか.
よろしくお願いします.
No.8ベストアンサー
- 回答日時:
例えば:
まずサブルーチンを用意します:
sub printSpecifiedLines {
my ($infile, $outfile, @subjects) = @_;
open(my $infh, '<', $infile) or return;
open(my $outfh, '>>', $outfile) or die "出力できない\n";
while (my $line = <$infh>) {
foreach my $subjects (@subjects) {
if ($. == $subjects){
処理
say {$outfh} $line;
}
}
}
}
入力ファイルがオープンできないときはだまって return するようにしてみました.
で, これを使う方では
open my $file, '<', 'line.txt' or die "can't open input $!";
chomp(my @subjects = <$file>);
close $file;
@dd_max = ( 0, 31,29,31,30,31,30,31,31,30,31,30,31 );
for ($mm=1;$mm<13;$mm++){
for($dd=1;$dd<$dd_max[$mm-1];$dd++){
for($hh=0;$hh<24;$hh++){
$filename = sprintf("2000-%2.2d-%2.2d_%2.2d.txt",$mm,$dd,$hh);
printSpecifiedLines($filename, "./out/$filename", @subjects);
}
}
}
で呼び出す, と.
とりあえず, これでファイルのオープン/クローズの整合性はとれるはずです. ここでは @subjects が全てのファイルで共通なのでメインの方で読み込んでますが, もちろんサブルーチンの方で読み込むという考え方もあります.
Tacosan様
ありがとうございます.毎度のことながらお礼をいくら言ってよいのかわからないほどです.実際にお会いして,感謝を伝えたいくらいです.
今後もお世話になるかもしれません.そのときもどうかよろしくお願いします.
ところで,Tacosan様がこれほどここで質問に答える理由はなんですか?
もし,よろしければお聞かせください.だめな理由があればいいですからね.
No.9
- 回答日時:
いや, とりあえず「どの質問に答えるか」ということについては「自分が答えられそうか」ということをまず考えて, その上でわりときまぐれですね.
ただ, 自分が答えておいて「わからん」と言われるとやっぱり気になるので, 一度答えた質問に対してはなるべく解決してもらえるとうれしいなぁ, と思うわけです.
あ, そうそう, サブルーチンじゃない方の for は多分 .. を使って
for my $mm (1 .. 12)
とか書いた方が Perl 的だと思います.
.... すみません, いくつかバグってますね. @dd_max の最初の 0 は消してください & $dd に対する範囲が間違ってます.
なるほど納得しました.そうですね,あのままだと2月から始まってしまいました.現在データの処理中です.2-3日はかかりますね.
ありがとうございました.回答を締め切ります.
お探しのQ&Aが見つからない時は、教えて!gooで質問しましょう!
似たような質問が見つかりました
- CGI htmlからパラメータで、cgiに渡したい。 1 2023/02/06 16:15
- C言語・C++・C# c言語の問題の説明、各所ごとに 5 2023/07/26 11:03
- その他(プログラミング・Web制作) Fortranでの出力ファイル 2 2023/03/21 21:25
- Ruby 教えてください 2 2023/01/04 17:50
- Perl perlのflock関数でロックをかけたままopen関数で何度もファイルを開きなおすことはできますか 3 2023/05/01 22:25
- その他(プログラミング・Web制作) pythonのこのエラーがわかりません 3 2022/11/16 14:54
- Excel(エクセル) Excelにて、フォルダ内のTextファイルをマクロで統合すると文字化けしてしまう時の解消コード 4 2023/01/01 07:32
- CGI perlで書いたcgiでsqliteの使い方を教えてください 2 2023/05/08 21:29
- Excel(エクセル) マクロでテキストファイルを読み込んだ際の最終セルにデータと改行が含まれる問題の改善方法 2 2022/03/25 16:50
- Visual Basic(VBA) エクセルのマクロについて教えてください。 4 2023/02/05 09:55
関連するカテゴリからQ&Aを探す
おすすめ情報
デイリーランキングこのカテゴリの人気デイリーQ&Aランキング
-
while文がうまく動かない
-
連番のファイルを何個も開きたい
-
Pythonでegrep機能をつかいたい
-
[perl] もっとシンプルに改良、...
-
文字列をカウントする方法
-
ファイル全てを .xlsm に変更し...
-
一定時間が経過したフォルダの削除
-
csvファイルの横方向への改行に...
-
while(<ハンドラ>) {} で行数を...
-
画像アップロード機能を追加し...
-
batファイルでrenameができませ...
-
VBAでCSVファイルの特定行を書...
-
MATLABのm-fileについて
-
配列のサイズを動的に拡張
-
ディレクトリのファイル作成を...
-
ANSI Cでファイル名、ディレク...
-
VB6.0でDB接続する際に切断時の...
-
Pythonの再帰関数の動作の流れ...
-
AutoCADのスクリプト
-
C++でファイルから複数行のデー...
マンスリーランキングこのカテゴリの人気マンスリーQ&Aランキング
-
ファイル名を複数個配列で確保...
-
Fortranで1行飛ばして読み込む方法
-
perlで指定範囲を複数ファイル...
-
Pythonでegrep機能をつかいたい
-
「パスが見つかりません」とい...
-
ifstream/ofstream について
-
テキストファイルの各行を配列...
-
Perlのワンライナーをスクリプ...
-
ifstream を利用した1行分のテ...
-
C++でのテキストファイル読み込...
-
perlプログラム 外部複数ファ...
-
system関数と引数について
-
Perl 重複カウント 上位3名
-
Pythonで非日本語のUnicode文字...
-
shellのコマンド deffの差分の...
-
perlで先頭の数値をみて昇順に...
-
Visual Basicを使って三平方の...
-
while文がうまく動かない
-
Perl Grepについて
-
Perlによるディレクトリ内の連...
おすすめ情報