プロが教えるわが家の防犯対策術!

Perl 初心者です。
過去ログのNo.285625 にもありましたが、ファイルの内容を一括して配列@xxに読み込んでprint "$xx[0]\n" とやっても一行目が表示されません。読み込みたいファイルはhtmファイルで一行目には<BR>で改行が入っているのですが、この一行が読めません。どうしたらよろしいのでしょうか?初歩的な質問で済みませんが、お願いします。

A 回答 (8件)

スクリプトの具体的な内容は、どのようになっていますか。

過去ログNo.285625の以下のスクリプトは、1行目を間違いなく表示します。
----------------------------------
open(IN,"A.txt");
@file = <IN>;
close IN;
print "$file[0]\n";
----------------------------------
尚、読みたいファイル("A.txtはカレントディレクトリにあることが前提です)。
特にopen時のhtmファイルの指定は、どのようになっていますか。
    • good
    • 0
この回答へのお礼

tatsu99 さま、ありがとうございます。
htmファイルはディレクトリとファイル名を指定して次のように開いて、配列@xxに格納されていることを確認できています。
open(IN,"$dirname/$dir");
@xx = <IN>;
close(IN);

問題は $xx[0]なんです。もし、成功したとして、htmテキストの表示部以前のヘッダーやボディー部をゲットしてしまうのでしょうか?
いっそのことindexやsubstrなどを使って、私が捉えたいhtm表示部の1行目の<BR>ではじまり</BR>で終わる部分だけを抜き出した方が適切でしょうか?ただし、こちらの書き方もどうも正しくできませんので。。。(全くの初心者なのです)

お礼日時:2003/09/27 23:56

#1です。

perlにとっての1行目とは、ブラウザで見える1行目では無く、ファイル上の改行文字(\n)を検知した時に、そこまでのデータが1行目となります。
従って、<BR>.../<BR>の...を抜き出すには以下のようにしてください。1行目に<BR>.../<BR>が含まれているというのが前提です。
------------------------------
if ($xx[0] =~ m#<BR>(.*)/<BR>#){
$data = $1;
printf ("<%s>\n",$data);
}
--------------------------------
$dataに...の部分が格納されます。
$xx[0]に<BR>で始まり/<BR>で終わる文字列が
無い場合は、このif文は成立しません。
    • good
    • 0
この回答へのお礼

tatsu99さま、ありがとうございました。引き続きお願いいたします。
 私はブラウザに表示される部分の一行目を何とかしてゲットしたいのです。それもソースでは最初に出現する<BR>..</BR>の..だけをです。
 配列@xxにhtmファイル内容を格納するよりも、htmソースはテキストファイルでしょうから、$textcontent=<FILEHANDLER>みたいに乱暴に格納できませんか?
 もしそれができれば、あとはindexやsubstrで検索できるのではないでしょうか?
 すみませんが、~ m#<BR>(.*)/<BR># って、いかにもPerLらしい表現ですが、まだ私には分かりません。
 質問の焦点が定まらなくて済みませんが、よろしくお願いいたします。

お礼日時:2003/09/28 00:51

#2の続きです。

ブラウザで見える1行目の内容の取得です。
------------------------------------
for ($i = 0; $i < 1000; $i++){
if ($xx[$i] =~ m#<BR>(.*)/<BR>#){
$data = $1;
printf ("<%s>\n",$data);
last;
}
}
-------------------------------------
前提としては、htmファイルのファイル上の何行目かに<BR>で始まり/<BR>で終わる行が、存在するという前提です。
必ず、同一行に<BR>と/<BR>があることが前提です。
スクリプトの意味は、以下の通りです。
1.下記処理を1000回繰り返す。(1000は安全の為)
2.各行に対して<BR>で始まり/<BR>で終わる文字列を検索する。
3.マッチしたとき、$1に<BR>.../<BR>の...の文字が格納されている。(正規表現のperlの仕様です)
4.lastは、繰り返しの打ち切り
--------------------------------
$textcontent=<FILEHANDLER>は1行単位で読み込みます。
@textcontent=<FILEHANDLER>は全行を一気に読み込み配列に格納します。
>あとはindexやsubstrで検索できるのではないでしょうか?
もちろん、その方法でもかまいません。
今回は、<BR>.../<BR>の...を抜き出す為に、上記の方法をとりました。indexを使う場合は、以下のようになります。
for ($i =0; $i < 1000; $i++){
$st = index($xx[$i],"<BR>",0);
if ($st < 0) { next; }
$en = index($xx[$i],"/<BR>",$st+4);
if ($en < 0) { next; }
$data = substr($xx[$i],$st+4,($en-$st-4));
printf ("<%s>\n",$data);
last;
}
    • good
    • 0
この回答へのお礼

tatsu99 さま。ありがとうございます!!教えてくださった二つの方法を貼り付けてやってみましたが、どちらも結果が何も現れません。
下は当初からお知らせしております自己流:
opendir(DIR, $dirname);
while (defined($dir = readdir(DIR))) {
 if ($dir =~ /\.s?html?$/ && index($dir, $todaystr)==0)
{
  print qq|<a href="$dirname/$dir">$dir</a>:|;
open(IN,"$dirname/$dir");
  @xx = <IN>;
  close(IN);

  for ($i =0; $i < 1000; $i++)
   {
   $str=$xx[$i];$aa=index($str,'<BR>');
   if ($aa>0)
    {
   $aa=aa+5;
   $str=substr($str,$aa,100);#about100
   print "$str<BR>\n";
   last;
    }
    }
}
}
closedir(DIR);
これですと結果の表示はあります:
9.26.1923 Ruhrkampf beendet.htm:"Layer3" align="left">9.26.1923: ルール闘争が終結
と出てはくれるのですが、なぜか、"Layer3...”なども出てしまいます。おかしいのはaaの位置か?substrがうまく働かないのか?どうも分かりません。

もちろん、できたら教えて頂いた正規表現を使いたいと思っていますが、不成功の原因は不明です。
どうか、御教示をお願いいたします。

お礼日時:2003/09/28 10:55

#3の続きです。


余談ですが、
$max = scalar(@xx);
とすると、配列の要素数が取得できますので、1000の代わりに$maxを使用してください。
    • good
    • 0

考えられる点についてコメントします。

 
  $str=$xx[$i];$aa=index($str,'<BR>');
   if ($aa>0)
    {
   $aa=aa+5;
   $str=substr($str,$aa,100);#about100
   print "$str<BR>\n";
----------------------------
1.$aa=index($str,'<BR>')は、成功時0以上の値となります。(先頭の位置は0)従ってif ($aa>=0)の方がベターです。(但し、この原因の本質的なものではありません)
2.$aa=aa+5;は、たぶん、エラーでしょう。
$aa=$aa+5;としてください。
但し、<BR>XXXのXの位置から、検索する場合は、
$aa = $aa + 4;となります。
3.ここからが、問題ですが、
$str=substr($str,$aa,100);#about100 は
<BR>以降の文字を無条件に100バイト取得しています。
そして、その中に、Layer3...の文字も含まれています。
substrの使用法に間違いがあるのではなく、htmファイル中にLayer3...の文字があるということになります。これは、HTMLのタグの一種だと思いますので、ブラウザでみた場合は、表示されないと思います。
perl自身はHTMLの構文には、関知しないので、取得したい文字を得る為には、HTMLのタグ文字を回避して、取得するようにperlに指定する必要があります。
4.素朴な質問ですが、以下の点について、教えてください。
1)通常、ブラウザで表示される先頭は、<title>...</title>の...なので、これを抜きだせばよいのかと思うのですが、いかがでしょうか。
2)<BR>は、<br>でも、HTML上有効だと思いますので、小文字の場合でも、ヒットさせる必要はないのでしょうか。
indexは、大文字、小文字を無視して、検索することは出来ませんので、index($str,'<BR>')でだめな場合、index($str,'<br>')も行う必要があると思います。(但し、今回は<BR>しかあり得ないということであれば、話は別です)

 
    • good
    • 0
この回答へのお礼

tatsu99 さま、ご親切にご説明頂きありがとうございました。おかげさまで、私のミスもわかり、所期の目的を達しました。正規表現てすごいですね。勉強になりました。ホントに初心者なので、苦労しましたが、アドバイスのお陰で信じがたいほど簡単にゴールインできました。今後ともよろしくお願いします。

お礼日時:2003/09/28 14:49

目的が分からないので質問内容がいま一つ飲み込めませんが、自己流の解釈ということで。


サイトマップの要約説明にでも使いたいのでしょうか?

それではうまくいかないと思いますので考え方を変えたらどうでしょう。
ともかくブラウザが表示した結果の1行目ということですよね?

HTMLはプログラム言語と違って記述が少々間違っていても
ブラウザが適当に判断してしまうので、正しいルールに則って厳密に書かれている保証はどこにもありません。
手書きならミスもあるでしょうし、HTML編集ソフト毎にいろんなクセがあるかもしれません。
それに</br>なんてタグは一部のバージョンを除き規定されていません。
XHTMLにはありますがどちらにしても空要素なので<br></br>のあいだに記述するのは誤りです。
といことで、何かのタグをキーワードに判定を行うの難しいです。

私が、掲示板スクリプトのメール返信機能で使用している方法です。HTMLタグを全部取り去ってます。
使っているのはPHPですが、perl用にチョコチョコッと改造しました。
テストはしていませんのでご自身で確認、必要な機能の追加を行ってください。

#!/usr/bin/perl

$file = "";# ファイルを指定するなり
# 自動で取得するなり自由に
open(IN, "$file");
@html = <IN>;
close(IN);
$count = $#html;
for ($i = 0; $i <=$count; $i++) {
# (1) 改行コードを取り去る
chomp($html[$i]);
# (2) インデントを抑制
$html[$i] =~ s# +<#<#g;
$html[$i] =~ s#\t+<#<#g;
# (3) タイトル取得 ()内は、ピリオド*
$html[$i] =~ s#<title>(.*)</title>#$1\n#g;
$html[$i] =~ s#<TITLE>(.*)</TITLE>#$1\n#g;
# (4) HTMLタグを取り去る
$html[$i] =~ s#<[^>]+(.*?)>#$1#g; # ()内は、ピリオド*?
# (5) HTMLエンティティを特殊文字に
$html[$i] =~ s## #g;
$html[$i] =~ s#&amp;#&#g;
$html[$i] =~ s#&lt;#<#g;
$html[$i] =~ s#&gt;#>#g;
if ($html[$i] ne "") {
print "$html[$i]\n";
}
}

# このままではタイトル行が初めに出力されます。不要なら<title>~</title>を正規表現で取り去ってください。
# 見かけ上は、<br>があったところで改行されていますが、プログラム上は元のHTMLが記述されたファイルの1行をそのまま1行として認識しています。
# 必要なら、別の配列に移しかえる等の工夫をしてください。
 改行コードの有無を判定して改行があるまで連結を繰り返せばいいです。
# (1)~(4)の順番は厳守のこと。
    • good
    • 0

#6です。

間違いがありましたので訂正します。

#!/usr/bin/perl

$file = ""; # ファイルを指定するなり
# 自動で取得するなり自由に
open(IN, "$file");
@html = <IN>;
close(IN);
$count = $#html;
for ($i = 0; $i <=$count; $i++) {
# (1) 改行コードを取り去る
chomp($html[$i]);
# (2) インデントを抑制
$html[$i] =~ s# +<#<#g;
$html[$i] =~ s#\t+<#<#g;
# (3) タイトル取得 ()内は、ピリオド*
$html[$i] =~ s#<title>(.*)</title>#$1\n#g;
$html[$i] =~ s#<TITLE>(.*)</TITLE>#$1\n#g;
# (4) <br><BR>を改行に変換
$html[$i] =~ s#<br>#\n#g;
$html[$i] =~ s#<BR>#\n#g;
# (5) HTMLタグを取り去る
$html[$i] =~ s#<[^>]+(.*?)>#$1#g;
# (6) HTMLエンティティを特殊文字に
$html[$i] =~ s## #g;
$html[$i] =~ s#&amp;#&#g;
$html[$i] =~ s#&lt;#<#g;
$html[$i] =~ s#&gt;#>#g;
if ($html[$i] ne "") {
print "$html[$i]\n";
}
}

# (1), (2)~(4), (5), (6) の順番厳守
    • good
    • 0

さらに #7に間違いが。

m(__)m

一番最後は、

print "$html[$i]";

です。どっちみちこのままでは使えないので、たいした問題ではありませんが。
    • good
    • 0
この回答へのお礼

Marionetteさま、すごい発想と汎用性へのご指摘、身にしみました。この発想で、書き換えに挑戦してみます。どうもご親切にありがとうございました。

お礼日時:2003/09/28 14:50

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