【復活求む!】惜しくも解散してしまったバンド|J-ROCK編 >>

perl初心者です。複数のファイルの処理について悩んでいます。

text-a
ab
ac
bc

text-b
a,1
b,2
c,3

とのような二つのテキストファイルで、
text-aの文字の中に、text-bの左の文字が含まれているとき
text-bの該当する文字の右側の数字を足して、text-aの右側に加えて書きだしたいです。

この例だと
ab 3
ac 4
bc 5
という風にしたいです。

open closeなどは省いています。text-aは実際は他にも情報があって、その分プログラムが多くなっていますが、$a1 = text-a の文字の部分になるようにしています。

while($str = <FILE_IN1>){
chomp($str);
@tmp = split(/\t/, $str);
@tmp1 = split(/,/, $tmp[0]);
@tmp2 = split(/,/, $tmp[1]);
$a1 = $tmp1[0];  

while($str0 = <FILE_IN2>){
chomp($str0);
@tmp0 = split(/,/ , $str0);
@b1 = @tmp0[1];
@b2 = @tmp0[2];

if($a1 =~ /$b1/){$a2 += $b2;}}

print FILE_OUT1 "$a2,$a2\n";
}

というプログラムを書いたのですが、数字を足して書き出す部分が上手くいかず、何故よくないのかさえわからない状態です...。
ご教示お願いします。

質問者からの補足コメント

  • ご指摘ありがとうございます。
    $b1 = $tmp0[1];
    $b2 = $tmp0[2];
    の書き間違いです。
    直すと、数字部分が全て1で表示されます。
    よろしければまた教えてください。

    No.1の回答に寄せられた補足コメントです。 補足日時:2017/11/13 08:34
  • 何度も小さなミスをすみません...。本当にありがとうございます。
    $b1 = $tmp0[0];
    $b2 = $tmp0[1];
    "$a1,$a2\n"
    で修正しました。
    open,closeは他のプログラムだと動いていたので問題ありません。

    $a2のクリアは、二つ目のwhileの前に
    $a2 = 0;
    かなと思ってやってみたのですが、
    次は$a2の表示が一番初めは1、
    後は全て0の表示になってしまいました...。

    No.2の回答に寄せられた補足コメントです。 補足日時:2017/11/13 14:45

A 回答 (4件)

うん, そうなってるだろうなと思った.



内側の while ループの動きを考えてみよう. まず, text-a.txt の 1行目のデータに対して FILE_IN2 から全データを読み込むよね. その次, text-a.txt の 2行目のデータに対して FILE_IN2 からデータを読み込もうとするんだけど, FILE_IN2 からはもう全てのデータを読み込んじゃってるのでそれ以上読み込めないんだよ.

3行目以降も全部同じことなので「後は全て0の表示になってしまいました...。」という結果になる, と.
    • good
    • 0
この回答へのお礼

一度全て読み込むと、次に読み込むときは
またファイルを開かないといけないんですね;
whileの中にopenを入れてopenも繰り返すようにしないといけなかったのですね。
無事に正しい結果を出すことができました。
知識が浅い私に、根気強く丁寧に教えてくださり、ありがとうございました。
とても勉強になりました。
本当にありがとうございました。

お礼日時:2017/11/14 16:32

本当にちゃんとできてるんだろうか....



open や close を含めたプログラムを見せてもらえませんか?
    • good
    • 0
この回答へのお礼

何度も、すみません。よろしくおねがいします。

use utf8;
use Encode qw/encode decode/;

open(FILE_IN1, "<:utf8", "text-a.txt") or die "Can't open file!";
open(FILE_IN2, "<:utf8", "text-b.txt") or die "Can't open file!";
open(FILE_OUT1, ">text-c.txt");

while($str = <FILE_IN1>){
chomp($str);
@tmp = split(/\t/, $str);
@tmp1 = split(/,/, $tmp[0]);
@tmp2 = split(/,/, $tmp[1]);
$a1 = $tmp1[0];  

while($str0 = <FILE_IN2>){
chomp($str0);
@tmp0 = split(/,/ , $str0);
$b1 = $tmp0[0];
$b2 = $tmp0[1];

if($a1 =~ /$b1/){$a2 += $b2;}}
$a1 = encode('UTF-8',$a1);
$a2 = encode('UTF-8',$a2);
print FILE_OUT1 "$a1,$a2\n";
}
close(FILE_IN1);
close(FILE_IN2);
close(FILE_OUT1);

お礼日時:2017/11/13 18:31

あ,


$b1 = $tmp0[1];
$b2 = $tmp0[2];
の添え字がたぶんおかしい.

あとは
・$a2 のクリアが書かれていない
・最後に表示するのは "$a2,$a2\n" でいい?
・ファイルの open, close はちゃんとできてるよね?
くらいかな.
この回答への補足あり
    • good
    • 0

@b1 = @tmp0[1];


とか
@b2 = @tmp0[2];
とかって, どうして配列を使ってるんですか?
この回答への補足あり
    • good
    • 0

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

このQ&Aを見た人はこんなQ&Aも見ています

このQ&Aと関連する良く見られている質問

Q複数ファイルの読み込みについて

perl初心者です。

あるディレクトリから拡張子がdataであるファイルを全て読み込みたいのですが、方法がわかりません。
cshで書くと
foreach arg (*.data)
コマンド $arg

のようになりますが、perlだと
foreach $arg (@arg){
コマンド $arg

となりますよね?
引数がリストなのでよくわかりません。
そもそもperlではできないのでしょうか?


それともう一点ですが、ファイルオープンするときに
foreachループの中で
open(FILE, "$arg");
とすることは可能ですか?
上の質問と組み合わせて全てのファイルを開いて作業を行いたいので。

説明が下手ですいません。補足しますのでよろしくお願いします。

Aベストアンサー

while(<*.data>)
{
## $_には、*.DATAなファイル名が格納されている。
open(F,"$_"); ##openする。
while(<F>)
{
##読み出された内容が$_に格納されている。
print $_; ##出力してみる。
}
}

というのが最短コーディングです。

QPerlで特定行から特定行までを抜き出したい

皆さんのお知恵をお貸し頂ければ幸いです。

Perlで以下のようなことをしたいと考えています。
例えば、次のようなテキストファイルがあったとします。

example.log
==================================
aaaa
hogehoge
test
okok
perl
script
==================================

上記ファイルを読み込んで、「hogehoge」から「perl」の間に挟まれた行だけ抜き出したいのです。
イメージとしては、読み込んだファイルを配列に入れて、一行づつ読ませ、キーワード「hogehoge」が現れたらそこでフラグを立て、それ以降の行を表示し、キーワード「perl」が現れた時点で表示を止めるという処理になるのかな?と思っています。

このような場合、どういう風にすればいいのでしょうか?
恐れ入りますが、ご教授頂ければ幸いです。

それでは、どうぞよろしくお願い致します。

Aベストアンサー

> 一行づつ読ませ、キーワード「hogehoge」が現れたらそこでフラグを立て、それ以降の行を表示し、キーワード「perl」が現れた時点で表示を止めるという処理になるのかな?と思っています。

それでいいと思いますよ?これをそのままコード化すると、こんな感じでしょうか。(No.1さんのとはちょっと結果が違います。)

open FH, "example.log" or die $!;
$flag = 0;
while ($data = <FH>) {
  chomp $data;
  if  ($data eq "hogehoge") { $flag = 1 }
  elsif ($data eq "perl")    { $flag = 0 }
  elsif ($flag) { print "$data\n" }
}
close FH;

で、もっと略したいPerlな人だとこんな感じ。Perl独特の記法がふんだんに使われているので、勉強するには不向きかもしれませんが^^;

open FH, "example.log" or die $!;
while (<FH>) {
  print if /^hogehoge$/ .. /^perl$/ and !/^(?:hogehoge|perl)$/;
}
close FH;

※インデントに全角空白を使っているので、コピーする場合はタブなどに置換して下さい。

> 一行づつ読ませ、キーワード「hogehoge」が現れたらそこでフラグを立て、それ以降の行を表示し、キーワード「perl」が現れた時点で表示を止めるという処理になるのかな?と思っています。

それでいいと思いますよ?これをそのままコード化すると、こんな感じでしょうか。(No.1さんのとはちょっと結果が違います。)

open FH, "example.log" or die $!;
$flag = 0;
while ($data = <FH>) {
  chomp $data;
  if  ($data eq "hogehoge") { $flag = 1 }
  elsif ($data eq "perl")    { $fl...続きを読む

QPerlで フォルダ内の全てのファイルを別のフォルダにコピーするには

お世話になります。
多分ご存知の方には簡単な話だと思いますが教えていただけませんか。
Aフォルダにあるhoge.txtをBフォルダにコピーしたければ
use File::Copy;
copy "./A/hoge.txt", "./B/hoge.txt" or die $!;
で出来るのはわかっているのですが、Aフォルダにある全てのファイルをBフォルダにコピーするというのはどのようなコードを書いたらよいのでしょう。
ちなみにAフォルダには100以上ファイルがあります。ファイルは全部テキストファイルです。

Aベストアンサー

$src_dir = "./a";
$dst_dir = "./b";

opendir(DIR, "$src_dir");
my @Files = grep { -f "$src_dir/$_" && /\.txt/ } readdir(DIR);
closedir DIR;

foreach my $file (@Files) {
copy ...
}

こんな感じですかね

Qperlプログラム 外部複数ファイルの読み込み処理について

perlプログラム 外部複数ファイルの読み込み処理について

あるフォルダに T0001_05_01,T0001_05_02,T0001_05_03,…,T0001_05_31 という31個のファイルがあります。
それぞれのファイルは 下記のような 形式で記述されております。
(例 T0001_05_01のファイルの中身)
2010-05-01 00:00:00.000 N00001 AAAAAA
2010-05-01 00:00:00.108 N00018 BBBBBB
2010-05-01 00:00:10.305 N00002 AAAAAA
2010-05-01 01:00:10.966 N00008 CCCCCC

また、別のlist.txtに 下記のようなユニークなリストが入っております。
AAAAAA
CCCCCC
WWWWWW

このとき、list.txtの値が それぞれT0001_05_XXファイルの何行目に出力されているか
出力するperlプログラムを作成したい。
(出力結果イメージ:1ファイル化)
T0001_05_01 1行目 2010-05-01 00:00:00.000 N00001 AAAAAA
T0001_05_01 3行目 2010-05-01 00:00:10.305 N00002 AAAAAA

T0001_05_31 10行目 2010-05-31 03:00:00.999 N00400 AAAAAA
T0001_05_01 4行目 2010-05-01 00:00:00.000 N00008 CCCCCC

perlプログラム知識がないものなので、このようなファイルの出力の仕方がわかりません。
教えていただけると助かります。

perlプログラム 外部複数ファイルの読み込み処理について

あるフォルダに T0001_05_01,T0001_05_02,T0001_05_03,…,T0001_05_31 という31個のファイルがあります。
それぞれのファイルは 下記のような 形式で記述されております。
(例 T0001_05_01のファイルの中身)
2010-05-01 00:00:00.000 N00001 AAAAAA
2010-05-01 00:00:00.108 N00018 BBBBBB
2010-05-01 00:00:10.305 N00002 AAAAAA
2010-05-01 01:00:10.966 N00008 CCCCCC

また、別のlist.txtに 下記のようなユニークなリストが入っ...続きを読む

Aベストアンサー

サンプルプログラムを作成してみたので試してみてください。
テストしていないのでうまく行かないことがあるかも知れません。

use strict;
open FH, "list.txt" or die "Can't open list.txt: $!";
my @keyword = <FH>; chomp @keyword;
close FH;
my ($day, @result) = ('00');

while (++$day lt '32') {
my $file = "T0001_05_$day";
open FH, $file or die "Can't open $file: $!";
while (my $line = <FH>) {
foreach my $i (0 .. $#keyword) {
if ($line =~ /$keyword[$i]/) {
push @result, [$i, "$day", $., "$file ${.}行目 $line"];
last;
}
}
}
close FH;
}

@result = map { $_->[3] } sort { $a->[0] <=> $b->[0] || $a->[1] cmp $b->[1] || $a->[2] <=> $b->[2] } @result;

open OUT, ">out.txt" or die "Can't open out.txt: $!";
print OUT @result;
close OUT;

サンプルプログラムを作成してみたので試してみてください。
テストしていないのでうまく行かないことがあるかも知れません。

use strict;
open FH, "list.txt" or die "Can't open list.txt: $!";
my @keyword = <FH>; chomp @keyword;
close FH;
my ($day, @result) = ('00');

while (++$day lt '32') {
my $file = "T0001_05_$day";
open FH, $file or die "Can't open $file: $!";
while (my $line = <FH>) {
foreach my $i (0 .. $#keyword) {
if ($line =~ /$keyword[$i]/) {
pus...続きを読む

QperlのNet::FTPで、ファイルかディレクトリか調べたい

現在、Perlでリモートバックアップする簡単なスクリプトを
書いています。

そのためにNet::FTPモジュールを使っているのですが、
use Net::FTP;
$ftp = Net::FTP->new($hostname);
$ftp->login($user,$pass);
$mydirs = $ftp->ls($backupdir);

のようにlsメソッドでファイル一覧を取得した後で、
各ファイルがファイルなのか、ディレクトリなのか
調べたいと思っています。しかしC言語のstat関数の
ようなメソッドはNet::FTPにはなさそうです。

どうすれば調べられるか、アドバイスいただけないでしょうか?

Aベストアンサー

メソッドdirを使って、パーミッション表示列を調べるとか。
あるいは、実際にgetして、失敗した時のプロパティmessageから判定するとか。

再帰的にgetできるコマンド(nctftpとかwgetとか)を使った方が手っ取り早そうですが。

Qファイルからデータを読み込んで、配列に格納する方法

データファイル grep.dat があり、その中は
12345
67890
ABCDE
(EOF)
となっています。
 
このファイルの中身を読み込んで、配列 P[0]の
中に("12345","67890","ABCDE") に格納したい
のですが、どのように記述すればよいでしょうか。

Aベストアンサー

多次元配列に代入する場合

my @p;
open FILE, "grep.dat";
  @{$p[0]} = <FILE>;  ・・(a)
close FILE;

openの書式などは好みで変えてください。
結論を言えば、(a)のように書けばokです。

#細かい書式は他にもありますので調べてみるといいかもしれません。

Qperlにて2つのファイル比較

いつもお世話になっています。
今回perlで2つのCSVファイルを比較して、マッチしたものをエクセルで表示させるスクリプトを作ろうとしています。
エクセルに表示するときに、OLE32を使うことは前回教えていただいたのですが、2つのファイルを比較する方法が分かりません;
ネットなどでは調べたのですが、参考になるサイトなど見つけられなかったので、詳しい方お力をお貸しください。
参考になりそうなサイトも教えていただけると、とても助かります。
よろしくお願いします。

Aベストアンサー

>一致した項目だけをエクセルで書き出したいのです

 CSVファイルでは、行のことを「レコード」、その行に含まれるデータ1つ1つを「項目」と呼びますが、その認識でよろしいでしょうか?
 ファイルAとBのレコードの数が一致しており、それぞれ1行ずつ読み込んで項目を順番に比較すればいいのであれば、

open(A, "<fileA");
open(B, "<fileB");
while ( <A> ) {
 @a = split(/,/,$_);
 @b = split(/,/,<B>);
 for($i = 0; $i < @a; $i++ ) {
  if ( $a[$i] eq $b[$i] ) {
   print "$a[$i]\t";
  }
 }
 print "\n";
}

 これでイケるはずです。
 でもこれだとデータの順番とかデタラメになっちゃいますけど、いいんですか?(^_^;
 最終的に何がやりたいのか分からないので、これ以上アドバイスしようがないのですが。

QUse of uninitialized value ---

初心者です。フォームに文字を入力してもらい、↓
print blockquote(
textfield(
-name => 'die Antwort',
省略----条件にあえば、
my $value = param('die Antwort');#として
if (($value eq $ans || $value eq $ans2) and ($c eq $num)){
「正解」と表示することにしました。すると、うまくいくのですが、
if (($value eq $ans || $value eq $ans2) and ($c eq $num)){
について「Use of uninitialized value ----」とApacheのerror logに書かれてしまいます。このためerror logがすぐに巨大なファイルになってしまいます。これを避ける方法をお教えください。よろしく、お願いいたします。

Aベストアンサー

コードに use warnings が入っているのですよね。
デバッグも済んでいるのでしたら、
no warnings qw ( uninitialized );
で、この警告の表示を抑制してもよいと思います。

Qperlで配列名を動的に作り出したい

試しに次のようにしてみましたがエラーになりました。

#!/usr/local/bin/perl
use strict;
use warnings;
my $mystr = "abcde";
my @{$mystr} = (1,2,3);

$mystrの内容はいろい変わっていきます。

ご存知の方いらっしゃいましたらすみませんが教えてください。
よろしくお願いいたします。

Aベストアンサー

なんでそんなことをしたいんですか?
ハッシュと無名リストへのリファレンス使って
my %a =() ;
$a{$mystr}=[1,2,3] ;
とかやった方がいろいろ便利だと思うんですが。
・変数名に使えない文字を$mystrに使える
・keys,each,exists等のハッシュを操作する関数が使える

Qperlの引数で複数のファイル処理をしたいのですが動作しません、教えて下さい。

perl 01.pl 01.txt 02.txtで01.txtと02.txtの二つのファイルを処理したいのですが方法が良く分かりません。以下のソースです。
@in1=<> # 01.txtを読む
@in2=<>; # 02.txtを読む
print @in2;

ここで、何もしなければそのままです。ここではどうやら標準入力からの入力待ちの状態になっています。なのでコントロールキーとZキーを打鍵してやると終わります。この時に、01.txtと02.txtの内容を表示しての終了となります。

理屈が分からない。
・何故、指定もしていないのにも関わらずに標準入力待ちになっているのか
・どうして、全てを表示する事になるのか

多分にこれは私がperlの動きを理解していないのが原因だとは思いますが。私の誤っている理解を御指摘願います。

Aベストアンサー

perl 01.pl 01.txt 02.txt
だと、
@in1=<> # 01.txtを読む
 ではなく、
@in1=<> # 01.txt と02.txt を読む
 になります。
その後
@in2=<> # 読むファイルが無くなっているので、標準入力から入力する
 となります。

print @in2;
 だと、何も表示されないはずです。
print @in1;
 だと、01.txt と 02.txt の両方が出力されます。

詳しくは
http://perldoc.jp/docs/perl/5.20.1/perlop.pod#I47O32Operators
> ヌルファイルハンドル <> は特別で、〜
等を参照してください。


<> ではなく、
@ARGVからファイル名を取得→ openで開く→読み込み→(close)
としてください。


人気Q&Aランキング