グッドデザイン賞を受賞したウォーターサーバー >>

初心者で至らぬ点が多々有りますが、宜しくお願いします。
環境はWindows7-64bit、ActivePerl 5.12.4 Build(64bit)を使用しています。
テキストが数百個有り、全て以下のような構成になっています。

文章1
文章2
文章3
kwd
文章4
kwd
文章5
文章6
kwd
   ~以下略~

ファイル郡をリストとして読み込み、それぞれのファイルに対して
kwdをキーとして検索し、該当した行の上の行を抽出しようとしています。

~ファイルリスト読み込みルーチンは省略、以下各ファイル毎のサブルーチン~

sub execute {
open(INP, "$inp"); #ファイル読み込み
open(OUT, ">rep\\$inp"); #ファイル書き出し(フォルダを変えて同名)

while(<IN>){
if($_ =~ m/kwd/){ #現在の行が"kwd"を含んでいたら
print OUT $prev; #前の行を抽出のつもり
}
$prev = $_; #現在の行データを$prevに格納
}
close(INP);
close(OUT);
}

$_には現在の行データが入っていると認識しており
上記の書き方で$prevには一段上の行データが入るのでは
と思ったのですが、現状$prevを出力してもカラです。

文法ミスよりも、そもそも考え方が間違っているような気がして
なりませんが、どうか解決法を教えて頂きたく。

このQ&Aに関連する最新のQ&A

A 回答 (5件)

りょ~かい.



でも, そうするとスクリプト全体とか使ったデータとかを見たいなぁ.
    • good
    • 1

サブルーチンを呼び出す側を想定してみたのが、


以下のスクリプトですが、スクリプトと同一フォルダにある
"input.txt"を使った限りでは正常に実行できています。

$input = "input.txt";
execute($input);

sub execute {
my ($inp) = @_;
open(INP, "$inp"); #ファイル読み込み
open(OUT, ">rep\\$inp"); #ファイル書き出し(フォルダを変えて同名)

while(<INP>) {
  if($_ =~ m/kwd/) { #現在の行が"kwd"を含んでいたら
    print OUT $prev; #前の行を抽出のつもり
  }
  $prev = $_; #現在の行データを$prevに格納
}
close(INP);
close(OUT);
}

※サブルーチン側の問題でないとすると、サブルーチンの呼び出し側に問題があるのかもしれません。
 「ファイル群をリストとして読み込み、」で、サブルーチンへのファイル名の引き渡しを
 どのように行っているか、具体的に示していただけないでしょうか?
    • good
    • 0

openがINPで、whileがINと コーディングミスしているだけの問題で


考え方は問題ないのでは。

この回答への補足

申し訳ありません。
ファイルハンドルに関しては投稿時の
推敲中に誤って消してしまったようです。
実際のファイルハンドルは同名です。

補足日時:2011/11/17 10:00
    • good
    • 1

 openでは、ファイルハンドルを"INP"としているのに、


入力するときは、"while(<IN>)"と異なったファイルハンドルに
しているので、入力データは何もないことになり、結果として
出力データ(ここでは$prev)には何も出てこないことになります。

 したがって、"open(IN, "$inp"); #ファイル読み込み"とするか、
"while(<INP>)"と変更すれば、出力データも出力されます。

この回答への補足

申し訳ありません。
ファイルハンドルに関しては投稿時の
推敲中に誤って消してしまったようです。
実際のファイルハンドルは同名です。

補足日時:2011/11/17 09:58
    • good
    • 0

「IN」というファイルハンドルは開けてないから, エラーになるかループが回らないかのどちらかのような気がするんだけど....



さておき, 「現状$prevを出力してもカラです」というのは
・どのように調べて
・どうなった結果
そう判断したのでしょうか?

この回答への補足

申し訳ありません。
ファイルハンドルに関しては投稿時の
推敲中に誤って消してしまったようです。
実際のファイルハンドルは同名です。

> >さておき, 「現状$prevを出力してもカラです」というのは~
に関してですが、出力したtxtの中身を見ての判断でしたが
正しくは「出力したtxtの中身は改行だけだった」です。
全く意味合いが違ってきますね・・・重ねて申し訳ありません。
なお改行数は、抽出元ファイル内部のkwd数と同数でした。

補足日時:2011/11/17 09:57
    • good
    • 0

このQ&Aに関連する人気のQ&A

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

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

このQ&Aを見た人が検索しているワード

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

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...続きを読む

Qファイルの行数取得

超初心者です。

いま、表計算的なスクリプトを記述しています。

あるファイルの行数を取得する関数ってあるんでしょうか?

ファイルに記述されている数値を足したり引いたりするのですが、forを使っての計算の際にファイルの行数が必要となりました。

Aベストアンサー

Perlにですね。ないはずです。
行数とはファイルに書かれた改行文字の個数ということなので
実際にファイルを全て読み込まないと行数はわかりません。
以下のように色々な方法があると思います

#### 単純な例
$a = 0;
open FD, "<file.txt" || die $!;
while (<FD>) {
$a++;
}
close FD;
print "行数:$a\n";

### 少しマニアックな方法
open FD, "<file.txt" || die $!;
@a = <FD>;
close FD;
print "行数:" . ($#a + 1) + "\n";


### 反則的方法(外部コマンド) ... UNIXの場合
print "行数:" . `wc -l file.txt` . "\n";

QPerlで行頭にある文字が含まれている行を全部削除して詰めたい

perl初心者です。以下のようにデータがならんでいる時、
test111 aaaaaaaaabbbbbbbbcccccc
test112 aaaaccccabbbbbbbbcccccc
test113 aaaaccaaabbbbbbbbcccccc
test114 acccaaaaabbbbbbbbcccccc

test111 aacaaaaaabbbbbbbbcccccc
test112 accaaaaaabbbbbbbbcccccc
test113 aaacccaaabbbbbbbbcccccc
test114 aaaaaccaabbbbbbbbcccccc

test112の行だけ削除して、さらにそこを詰めたい時のスクリプトを作成しています。

途中からわかりません。
行を削除する関数が調べても見つからないのです。

#!/usr/bin/perl ;
open(IN, "test.doc") or die ;

open(OUT, ">testout.doc");

while(<IN>) {
chomp ;
if (/(\S+)/) {

$name = $1 ;

if ($name =~ /^test112(\S+)/) {
#ここでマッチさせて、一気に行を削除して、しかも行を詰めたいのですが

;

}
print OUT " \n" ;
}
}
close (IN) ;
close (OUT) ;

大変困っております。宜しくお願いします。

perl初心者です。以下のようにデータがならんでいる時、
test111 aaaaaaaaabbbbbbbbcccccc
test112 aaaaccccabbbbbbbbcccccc
test113 aaaaccaaabbbbbbbbcccccc
test114 acccaaaaabbbbbbbbcccccc

test111 aacaaaaaabbbbbbbbcccccc
test112 accaaaaaabbbbbbbbcccccc
test113 aaacccaaabbbbbbbbcccccc
test114 aaaaaccaabbbbbbbbcccccc

test112の行だけ削除して、さらにそこを詰めたい時のスクリプトを作成しています。

途中からわかりません。
行を削除する関数が調べても見つからないのです。

...続きを読む

Aベストアンサー

一致しなかったときのみ出力するということで、

while(<IN>){
unless(/^test112/){
print OUT;
}
}

更に簡単に書くと、
while(<IN>){
print OUT unless(/^test112/);
}
となります。

削除にこだわるなら、
while(<IN>){
s/^test112\s.+//;
print OUT;
}
あたりでしょうか。

もしくは、明示的に削除したいなら、
while(<IN>){
if(/^test112\s.+/){
$_ = "";
}
print OUT;
}
というふうに、カラの文字列を代入してやるのも、値を削除するときの常套手段ですね。

Q大量データから抽出する効率よいperlプログラムは

以前も質問させていただきましたが、
大量データから抽出する際の効率よいperlプログラム作成について
また、教えてください。
例)
大量データ Aファイル 3列 可変値(数値、URL、数値)タブ区切り 重複値あり
123 http://www.XX.co.jp/XX 4567
1111 http://www.XX.co.jp/XX 3333
3 http://www.XX.co.jp/YZ 4567
1111 http://www.YYY… 116

抽出対象データ Bファイル 1列(URL)重複なし
http://www.XX.co.jp/X
http://www.YYY.co.jp


BファイルにあるURLで始まるURLがAファイルにある場合 Aファイルのその行を抽出したい。
grepで実施すると すごい時間がかかってしまうため、効率よい抽出方法をおしえてください。
今回は、完全一致ではなく、Bファイルに入っているリストのURLから始まるものにしたいと考えているので、前の手法(hash連想配列)が使えないと考えております。
Aファイルが容量大きいため、grep処理では1週間たっても終わらないのです。

以前も質問させていただきましたが、
大量データから抽出する際の効率よいperlプログラム作成について
また、教えてください。
例)
大量データ Aファイル 3列 可変値(数値、URL、数値)タブ区切り 重複値あり
123 http://www.XX.co.jp/XX 4567
1111 http://www.XX.co.jp/XX 3333
3 http://www.XX.co.jp/YZ 4567
1111 http://www.YYY… 116

抽出対象データ Bファイル 1列(URL)重複なし
http://www.XX.co.jp/X
http://www.YYY.co.jp


BファイルにあるURLで始まるURLがAファイルにある場合 Aフ...続きを読む

Aベストアンサー

本当に終わるか気になったので、自分のPCで試してみました。
メモリ4Gであれこれ普通に使いながら、次のものです。
ただ、内一個は途中でやめちゃいました。

まず、こんなかんじでdummyファイルを作りました

Ruby
# dummy作成
http://ideone.com/TDxut
→1Gバイトで約2000万件の嘘データ
# フィルタ元リスト作成
→dummyの頭50件の、URL内ドメイン箇所までのリスト

Ruby
# 文字列マッチ
http://ideone.com/xPsku
→約25分

# 正規表現マッチ
http://ideone.com/kvSff
→途中でやめた為不明

GNU/grep
# grep -F -f 元リスト.txt dummy.txt
→1分弱!


ということで、少なくともRubyでは全く太刀打ちできませんでした。
でも、終わる分量ではあると思います。特にPerlならきっともっと早いんでしょう
やっぱりgrepがおすすめですね

Qテキストファイルの本文中に行番号を挿入するperlスクリプトを探しています。

テキストファイルの本文中に行番号を挿入するperlスクリプトが有る、と聞いて探しているのですが、見付かりません。何か手掛かりをご存知の方がいらっしゃいましたら、ご教示をお願いいたします。

※「本文中に行番号を挿入する」とは、(テキストエディタやOSなどの)環境・設定が異なる人同士で情報交換する際でも、同じ行番号で同じ行を特定できるようにすることを意図しています。

Aベストアンサー

$. が「現在の行番号」を表します. で, $_ が「読み込んだ行」なので "$.: $_" で「読み込んだ行の前に行番号を追加する」ということになります.
あと, 書式が必要なら指定できる printf もちゃんと用意されてます. 使える書式はだいたい C と同じです.
ということで Leopard なら
perl -ne 'printf "%06d: %s", $., $_' ファイル名
でいいし, Windows でも
printf "%06d: $s", $., $_ while <>;
というスクリプトを書いて
perl スクリプト ファイル名
で OK.
ただし複数のファイルを一度に処理しようとすると行番号が「前のファイルの続き」になるのは同じ.

Q○文字目に文字挿入

お世話になっています。
正規表現の文字置換s///gを使って数字の3桁目に-を挿入したいですが、どうしたらいいのかわかりません。

どなたか教えていただけないでしょうか。

5770001

577-0001

にしたいのでしが…

Aベストアンサー

試してないのですが
s/(.{3})(.*)/$1-$2/;
でよいはずです。

数字確定ならば\dでも可。

QPerlで別ファイルから文字列の抽出

当方、サーバ管理でインフラ系の経験しかなく、今回はperlでスクリプトの作成に挑戦しておりますがなかなか理解できていません。お知恵をお貸しください。

やりたいこと:
ある入力を受けたら、別ファイルに照会して特定列の文字列を抽出する。以下に例を示します。

入力が gad の場合(小文字です)、file1を参照する。例では一行目にGAD****があるのでこれに該当することとする。最終的にoffice が出力されるようにしたい。


file1の内容:
GAD93911 <test1> office
HOA14845 <test2> desk
ABC52311 <test3> chair
KFI33823 <test4> home

よろしくお願いいたします。

Aベストアンサー

ファイルを開いて、各行を順番に /$in\d+\s<\w+>\s(\w+)/iでマッチするものを取り出して、それを使う・・

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 $_; ##出力してみる。
}
}

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

Qファイルの3行目までを出力したい

Perl初心者です。
test.txtというファイルがあって、その中の1行目から3行目までを
出力したい場合はどうしたらいいでしょうか?

open(FILE,"test.txt") || die "Open Error.\n";
@data = <FILE>;
close(FILE);

foreach (@data) {
print $_;
}
これだと、ファイルの中身が全て出力されてしまいます。

Aベストアンサー

@dataというのは配列で、1つの要素が1行になっています。
つまり、
foreach 1周目: $_ → $data[0] … 1行目
foreach 2周目: $_ → $data[1] … 2行目
foreach 3周目: $_ → $data[2] … 3行目
foreach 4周目: $_ → $data[3] … 4行目
というわけです。

やりかたはいくつかありますが、今後のことを考えると
新しくスカラー型の変数を用意してforeach内部のループ回数を数えるようにすると
勉強になると思います。

$count = 0;
foreach (@data) {
 print $_;
 # * count増加
 # * countが3になったらループを抜ける
}

for文を使って同じことをしてみるのも勉強になると思います。

Qひとつの命令を複数行に記述

検索してもあまり解説見かけないなぁと思うのですが、(どこが本家かわからないのでとりあえず放置)

VBでいう_に該当するものは何ですか?
ソースが長くなって見にくくなっているので、対処したいのですが。

hoge = "じゅげむじゅげむごごうのすりきれ" _ '←次の行に送る
& "かいじゃりすいぎょのうんらいまつふうらいまつすいぎょうまつ" 

Aベストアンサー

Perlは、VBと異なり行の概念がありません。
VBではステートメント区切り子が存在しないため、改行がステートメントの区切りとして扱われ、例外的につなげるときに「_」を使うわけですが、
Perlの場合はステートメント区切り子セミコロン「;」がステートメントの区切りになっていますので、セミコロンを打たない限り、何行に分かれてもひとつのステートメントとして扱われます。
したがって、回答としては「そのまま改行してOK」です。
上記の例なら、

$hoge = "じゅげむじゅげむごごうのすりきれ" .
"かいじゃりすいぎょのうんらいまつふうらいまつすいぎょうまつ";

という感じです。
当然ながら、文字列中での改行はダメなので、上記のようにいったん「"」を閉じて、文字列結合演算子「.」で接続することに成ります。


人気Q&Aランキング