PC-Blues # 043 もっと書き換え。

以前、ホームページを全部まとめて書き換えるはなし。で、結局Perlに頼って、ディレクトリ内の全部のファイルを総書き換えしたことがあった。あれから、二年弱。再び、のびのエーちゃんから、依頼があった。

前回の書き換えではhtmlの<head>〜</head>に<script>でjavascriptを打ち込み、ブラウザがIEであれば、<bgsound>を挿入、そうでなければ、<embed>を挿入して、midiを送りこみ、javascriptを使用していない相手には<body>〜</body>に<noscript></noscript>を使って、<bgsound>埋めこむ、という凝ったシロモノを作った。

が、midiは音源の違いが大きく、ことにウインドウズ標準のmidiはドラムを中心に実にチャチな音がするので、いっそMP3に換えたいとのことであった。とはいえ、いきなりMP3では重すぎるし、midiのよい音源をもっている人はそちらのほうがよいから、旧来のmidiも再生したいとのこと。

結局、今回の書き換えは、<head>〜</head>にある<script>〜</script>を全削除し、<noscript>〜</noscript>の中にある<bgsound>を<embed>に書き換え、さらに、そこからファイル名をとり出して、拡張子をmidからmp3に換えて、もう一つ<embed>を加えてこちらに書き込むというものである。

今回は書き換えは先方で行うので、向こうにはPerlはあるが、sedはない。Perlをsedのように使うスイッチもあるが、sedというやつは実にワケのわからないソースができるので、フツーのPerlのスクリプトを書いたほうが無難である。これなら、スクリプトを適当なフォルダにいれてダブルクリックで、「ハイできあがり」である。

前回のスクリプトはこんなものである。今回の問題点はこれでは、一行ごとに作業するために、何行にも離れて書かれている、<script>〜</script>などを取り扱えない。こういう場合は

undef $/;
$_ = <IN>;
などとやる。前回は while(<IN>)とやったのであるが、これは何も言わなければ区切り文字として、 $/="\n";がセットされているために一行ずつの処理になるのである。そこで、undefを使ってこれを無効にする。こうすることで$_ = <>;で一気にファイルの全行を読み込むことができるようになる。

このあと、「s///ig」を使って書き換えるわけだが、何せhtmlだから、「/」が頻出してしまう。こんなときは「s| | |」とか「s! ! !」とかsの後の文字を換えてやると/の代用に使用できる。

また「s| | |」もそのままでは"."が改行文字を含めてくれないので、複数行にわたる、例えば、

<script>
……
</script>
こういう行を書き換えたいといった場合にうまくマッチしない。こんな用途にはsスイッチを使う。
s|<script>.*?</script>||sig;

などとやる。なお、.*?の最後の?は最小マッチであり、これがないと二つ以上 <script> …… </script> があった場合に一つめの<script>から最後の …… </script>を削ってしまうハメとなる。

また、iスイッチは大文字小文字の区別をしないためである。

gスイッチはグローバルマッチで、何箇所<script> …… </script>があってもその全てを書き換える。結局sigと文末に並べることになる。

あとは

<NOSCRIPT> <bgsound loop="1" src="midi/believe.mid"> </NOSCRIPT>

<embed loop="false" hidden="false" autostart="true" src="http://utagoekissa.web.infoseek.co.jp/midi/believe.mid">
<embed loop="false" hidden="false" autostart="false" src="http://utagoekissa.music.coocan.jp/MP3/believe.mp3">
と書きかえれば、ことはたりる。 これは、
s|<noscript.*?src=\"midi/(.*?)\.mid\".*</noscript>|<embed loop=\"false\" hidden=\"false\" autostart=\"true\" src=\"http://utagoekissa.web.infoseek.co.jp/midi/$1.mid\">\n<embed loop=\"false\" hidden=\"false\" autostart=\"true\" src=\"http://utagoekissa.music.coocan.jp/MP3/$1.mp3\">|is
とでもすればよい。

ところが、である。早々に問題が発生した。何のことはない。IEには<embed>は鬼門なのである。2003年のおりはそれゆえに、<bgsound>の両使用をjavascritptで切り替えたのである。またぞろ2、3曲も聞くとハングするマシンが続出したらしい。

さてどうするか。もとのままで、mp3だけは<a>タグでリンクするという手もあるが、その場合はもとのページがmidiを鳴らし、新しリンク先がmp3を鳴らすというハメとなる。一曲につき二枚のhtmlを準備して、それぞれmidiとmp3のタグを書くという手もあり、同様に歌詞のhtmlにはどちらのタグもいれず、小さなhtmlフレームにタグをいれて、これをリンクで呼ぶという手もある。しかし、これでは1000曲からある曲に対しそれぞれに2〜3枚のhtmlをもつことになる。管理があまりにタイヘンというものである。

こうまで数が増えているのだから、プログラムを使用するのが順当であろう。cgiかphpで雛形をつくり、曲名とmidiまたはmp3の別を引数であたえる。これが素直な気がする。そんなわけで、ただし相手はプログラムに慣れていない。その人にとってメンテしやすいものでなければならない。たぶん、perlでしこしことprint命令を頻発するくらいならphpにして、あらかたhtmlの体裁をとり、ちょんもりとプログラム部分を埋め込んだほうがラクであろう。ただ、phpはずいぶん普及したとはいってもサポートしていないサーバーもある。向こうのホームにしているinfoseekはサポートしておらず、2ndにしているniftyはサポートしている。よってniftyのほうをホームとすれば問題はない。

というわけでphpに手を出すことにした。これが処女作でそれを他人様にあげようというのだからわたしもいい度胸である。ところが、最初は乗り気であったエーちゃんから、やっぱりやめようと思うとメールが来た。これをやると新しいurlは

http://utagoekissa.music.coocan.jp/utagoe.php?title=believe&type=mp3

というふうなurlになるのだが、これまでのurlで直接リンクをもっている人もあり、このhtmlで検索をエンジンを動かしていることもあり、もとのhtmlを移動したくない由。

そういうことなら、元のurlから、新しいurlへ、jumpさせるなり、linkをはるなり、古いhtmlはそのままにおいておくなり手はあるのだがついつい野心が動いてしまう。つまり、infoseekのhtmlをniftyのサーバーから読みとり、書き換えて、表示するプログラムである。perlの場合ならば、縦書きで紹介した、lib_wwwをuseするのだが、phpは何もしなくても

$contents = file_get_contents();

にurlを入力するだけである。getやpostの読み込みも$_GET[val]で勝手に連想配列にはいってくれる。splitして押しこむ手間なしである。これは便利である。エライぞphp。というわけで作成したのがこれである。

ところが、である。これをやると、テキスト内のリンクが一部おかしくなるとのこと。それはそうである。http://のついている絶対リンクはそのままでよいが、相対パスがついていれば、元ディレクトリがちがっているのだから当たり前である。これは元のファイル群の絶対パスのはそのままに、相対パスのうちカレントディレクトリの曲名ファイルにつながっているものはhttp://utagoekissa.music.coocan.jp/utagoe.php=?の形に直してやれなければならない。

こういう作業はやはり、前回の書き直しPerlのほうがラクである。よって今回の書き換えはこんなかんじになった。

というわけで、話が二転三転した結果、phpというものをはじめるハメとなったが、これはいいわ。いままで手をつけてなかったのが勿体ないという感じである。というわけで、Perlのcgiに断固としてこだわる必要もなさそうである。ただし、Perlのないサーバーはめずらしいが、phpの使えないサーバーは結構ありそうであるからその場合はいたしかたない。


###########昔の書き換えスクリプト。ここから############################
#!/usr/bin/perl
#註)汝の責任にて使用されたし。
#これを使用してどんな損害がでても作者は責任をもてません。
$input="html";      # 入力するファイルの拡張子
$output="html";      # 出力するファイルの拡張子
$inputdir=".";      # 入力するファイルのディレクトリィ
$outputdir="$inputdir/output";      # 出力するファイルのディレクトリィ
#####################################################################
#註) 拡張子か、ディレクトリィを入力と出力でずらすようにしてください。
########################################################################
opendir DIR ,"$inputdir";                     # 入力ディレクトリィを開く。
@dir = readdir DIR ;                  # 入力ディレクトリィを読む。
@list = grep {/^.+\.$input$/} @dir;   # xxxx.htmlというファイルだけにする。
closedir DIR ;                       #入力ディレクトリィを閉じる。 
unless(-d $outputdir){               #出力ディレクトリィがなければ作る。
    mkdir $outputdir,0700;
}
foreach(@list){                      # xxxx.htmlのxxxxの部分だけとりだす。
    s|^(.*).$input|$1|;
    @file = (@file ,$_);
}
foreach(@file){
#すべての入力ファイルについて以下の動作をくりかえします。
    open IN ,"$inputdir/$_.$input";            #入力ファイルをオープンする。
    open OUT ,">$outputdir/$_.$output";         #出力ファイルをオープンする。
    while(<IN>){
s|<embed (.*)src=(.*)|<object $1data=$2|;
# ↑ここで
#入力ファイルを一行読んでは書き換えて(またはそのまま)出力ファイルに書き込みます
# s|書き換える文字列の正規表現|書き換え後の文字列| とします。改行は"\r\n"です。
# たとえば、s|おばさん|おねえさん|gと書けば文章中のすべての「おばさん」が
#「おねえさん」になります。
# 正規表現はいろんなエディタで使えますから覚えておくとトクします。
# これは「 <embed ナンタラ src= カンタラ 」という文字列を
#「<object ナンタラ data= カンタラ 」という文字列に書き換えています。 
      print OUT $_;
    }
    close IN;                     #入力ファイルを閉じます。
    close OUT;                    #出力ファイルを閉じます。
}

###########ここまで############################

##########ここから#############################
#!/usr/bin/perl
$input="html";      # 入力するファイルの拡張子
$inputdir = ".";    #入力ファイルのディレクトリ
$outputfile=".html"; #新らしいファイルの名前の後半部と拡張子。
$outputdir="NEW";    #新しいファイルを入れるディレクトリ。
undef $/ ;           #一気にファイルをまるごと読む工夫。
###########################################################
#MP3用のhtmlを作成する
opendir DIR ,"$inputdir";                     # ディレクトリィを開く。
$flag = mkdir $outputdir ;# 新しいファイルのためのディレクトリをつくる。
print "フォルダを新規作成しちゃったぞ\n" if($flag);
@dir = readdir DIR ;                  # ディレクトリィを読む。
@list = grep {/^.+\.$input$/} @dir;   # xxxx.htmlというファイルだけにする。
foreach(@list){                      # xxxx.htmlのxxxxの部分だけとりだす。
    s|^(.*)\.$input|$1|;
    @file = (@file ,$_);
}
foreach(@file){
    open IN ,"$_.$input" or die "ううむ開くファイルがないわい。";            #入力ファイルをオープンする。
    open OUT ,">$outputdir/$_$outputfile" or die "すまん死んだ。";         #出力ファイルをオープンする
    $_ =<IN>;
#ここから書き換え部分でございます。
	s|<a[^>]+href=\"([^/]*)\.html?\"|<a href=\"http://utagoekissa.music.coocan.jp/utagoe.php?title=$1\"|gsi; 
#↑<a href="hogehoge.html" または <a href="hogehoge.htm" を 
#<a href=http://utagoekissa.music.coocan.jp/utagoe.php?title=hogehogeに書き換える。
#sオプションをつければ、複数行にまたがっても平気。
	s|<a[^>]+href=\"./([^/]*)\.html?\"|<a href=\"http://utagoekissa.music.coocan.jp/utagoe.php?title=$1\"|gsi; 
	s|<a[^>]+href=\"/([^/]*)\.html?\"|<a href=\"http://utagoekissa.music.coocan.jp/utagoe.php?title=$1\"|gsi; 
	s|<a[^>]+href=\"http://utagoekissa.web.infoseek.co.jp/([^/]*)\.html?\"|<a href=\"http://utagoekissa.music.coocan.jp/utagoe.php?title=$1\"|gsi; 
#↑/hogehoge.htmとか、./hogehoge.htmlとか、http://utagoekissa.web.infoseek.co.jp/hogehoge.htmlとかそういうのをhttp://utagoekissa.music.coocan.jp/utagoe.php?title=hogehogeに書き換える。
    print OUT $_;
    close IN;                     #入力ファイルを閉じます。
    close OUT;                    #出力ファイルを閉じます。
}
print "できあがり\n";
#↑終了メッセージ。
#########ここまで################
##### php title=で曲名をもらって type=でmidiとmp3をわけて、よそから文をとってくるphp########
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=x-sjis">
<meta name="GENERATOR" content="Micmic powered php system">
<?php
print "<title>$_GET[title]  phpバージョン</title>";
?>
<SCRIPT type="text/javascript">
<?php
	$title = $_GET[title];                           //urlのtitle=××を読みとる。
	if ($_GET[type] == "mp3"){                       //type=××を読んで、mp3だったときの処理。
	$path = "http://utagoekissa.music.coocan.jp/MP3";//mp3ファイルのある場所。
	$ext = ".mp3";//mp3ファイルの拡張子
	}else{                                           //type=mp3ではなかった場合の処理。
	$path = "http://utagoekissa.web.infoseek.co.jp/midi";//midiファイルのある場所。
	$ext = ".mid";                                   //midiファイルの拡張子。
	} 
	echo "
<!--
if (navigator.appName == \"Microsoft Internet Explorer\")
{
document.write(\"<bgsound loop=\\\"1\\\" src=\\\"$path/$title$ext\\\">\")
}
else
document.write(\"<embed loop=\\\"false\\\" hidden=\\\"true\\\"  autostart=\\\"true\\\"  src=\\\"$path/$title$ext\\\">\")
//-->
	";
?>
</SCRIPT>
 <style type="TEXT/CSS">
 <!--
 a:hover      { color: #ff3366;}
 a{ text-decoration:none; }
 body{ margin-top:0pt;}
 -->
 </style>

</head>
<body background="image/nobi2.jpg" text="#000000" link="#0000FF" vlink="#800080">
<NOSCRIPT>
<?php echo"
<bgsound loop=\"1\" src=\"$path/$title$ext\">
"?>
</NOSCRIPT>

<?php
print "<p><a href=\"$_server[SCRIPT_NAME]?title=$title&type=midi\"><img src=\"MIDIlogo.jpg\" alt=\"midi\">はこちら</a>
  <a href=\"$_server[SCRIPT_NAME]?title=$title&type=mp3\"><img src=\"MP3logo.gif\" alt=\"mp3\">はこちら</a>";
if($ext == ".mp3"){                             //もし$ext(拡張子)が.mp3なら
echo "<p>ただいま<strong>MP3</strong>で演奏中";//MP3演奏を表示
}else{                                         //そうでなければ
echo "<p>ただいま<strong>MIDI</strong>で演奏中"; //midi演奏と表示。
}
$html="http://utagoekissa.web.infoseek.co.jp/$title.html"; //歌詞と解説のファイルを決定する。
$contents = file_get_contents($html); //それを読みこむ。
$contents = preg_replace("'\n'","<meta>",$contents);  //改行を<meta>でおきかえ
$contents = preg_replace("/<!doctype.*<\/noscript>/i","",$contents);//頭から<noscriptまでを切り落とす。
$contents = preg_replace("'</body>.*</html>'i","",$contents); //おしりのタグを切り落とす。
$contents = preg_replace("'<meta>'","\n",$contents); //<meta>を改行に戻す。
print $contents;                                     //テキストを出力
?>
</body>
</html>



#################################

[前へ] [次へ]
[Home] [目次]

2006/02/07