◇ 正規表現実験室2

正規表現実験室のおかげで、管理人の正規表現レベルは4くらいになりました。サイトのねたにもなり、自分の正規表現レベルもあがる、なんて画期的な企画なんだと感心しながら早速第2段の作成にとりかかりました。正直、第1段では実験と称して基本の復習ばかりしていました。ここからは正真正銘実験の繰返しでいこうと思っています。目指す達人のレベルが100だと考えると…まだまだ先は長い(笑)

早速なんですが、CSVファイルにテーブルタグを加えて表に加工するプログラムを作りたいなと。こんなサイトを運営していますとこのような要望が出てくるわけです。情報量の多い表を作成する場合、個々のデータはエクセルを使用して作成し、最終段階でHTMLの表に直せば、データの入力は楽なのではないかと思いまして、よくチャレンジはするのですが、結局最後には手作業になってしまっています。行う作業といえば、「,」を「</td><td>」に一括置換し、行の先頭に「<tr><td>」、行末に「</td></tr>」を手作業で貼り付けていく作業になるのですが、こんなこと正規表現を使用すればおそらくあっという間にできるに違いないと、やってもないうちから思っているわけです。では早速チャレンジします。

my($csvFile) = './test.csv';
open(CSV, "$csvFile") || exit(0);
while(<CSV>){
   s/,/</td><td>/;
   print;
}
close(CSV);
exit(0);

だめでした…と思えばおかしなところを発見。</td>の中に置換の区切り文字である「/」があるではないですか。前実験室での経験が活かされていないと反省しつつ再チャレンジ。

my($csvFile) = './test.csv';
open(CSV, "$csvFile") || exit(0);
while(<CSV>){
   s/,/<\/td><td>/;
   print;
}
close(CSV);
exit(0);
SampData1-1</td><td>SampData2-1,SampData3-1
SampData1-2</td><td>SampData2-2,SampData3-2
SampData1-3</td><td>SampData2-3,SampData3-3

うまくいったと思ったのもつかの間で、それぞれの行で一回ずつしか置換されていません。再チャレンジ。

my($csvFile) = './test.csv';
open(CSV, "$csvFile") || exit(0);
while(<CSV>){
   s/,/<\/td><td>/g;
   print;
}
close(CSV);
exit(0);
SampData1-1</td><td>SampData2-1</td><td>SampData3-1
SampData1-2</td><td>SampData2-2</td><td>SampData3-2
SampData1-3</td><td>SampData2-3</td><td>SampData3-3

やっと「,」だけは置換できました。次に先頭に「<tr><td>」を挿入する実験なんですが、「$_ .= "<tr><td>";」で十分だという突っ込みは無しにして頂いて、あくまで正規表現の実験と言うことで話を進めたいと思います。

my($csvFile) = './test.csv';
open(CSV, "$csvFile") || exit(0);
while(<CSV>){
   s/^/<tr><td>/;
   s/,/<\/td><td>/g;
   print;
}
close(CSV);
exit(0);
<tr><td>SampData1-1</td><td>SampData2-1</td><td>SampData3-1
<tr><td>SampData1-2</td><td>SampData2-2</td><td>SampData3-2
<tr><td>SampData1-3</td><td>SampData2-3</td><td>SampData3-3

最後に行末に「</td></tr>」を加えて完成です。これも純粋に正規表現の実験ということで(笑)

my($csvFile) = './test.csv';
open(CSV, "$csvFile") || exit(0);
while(<CSV>){
   s/^/<tr><td>/;
   s/,/<\/td><td>/g;
   s/$/<\/td><\/tr>/;
   print;
}
close(CSV);
exit(0);
<tr><td>SampData1-1</td><td>SampData2-1</td><td>SampData3-1</td></tr>
<tr><td>SampData1-2</td><td>SampData2-2</td><td>SampData3-2</td></tr>
<tr><td>SampData1-3</td><td>SampData2-3</td><td>SampData3-3</td></tr>

なんとか正規表現を使用してテーブルタグの挿入が完成しました。ここで、「^」は行の先頭を表し、「$」は行末を表しています。しかし、ここまできたら何とか1行でかっこよく表現してみたいものです。1行で表現したからかっこいいかどうかは別として、とりあえずチャレンジ。

my($csvFile) = './test.csv';
open(CSV, "$csvFile") || exit(0);
while(<CSV>){
   s/^([^,]+),(.+),([^,]+)$/<tr><td>\1<\/td><td>\2<\/td><td>\3<\/td><\/tr>/g;
   print;
}
close(CSV);
exit(0);
<tr><td>SampData1-1</td><td>SampData2-1</td><td>SampData3-1
</td></tr><tr><td>SampData1-2</td><td>SampData2-2</td><td>SampData3-2
</td></tr><tr><td>SampData1-3</td><td>SampData2-3</td><td>SampData3-3
</td></tr>

いい線いってたのですが、改行まで消してしまってますね。今回使用しました「()」なんですが、これ結構使えます。「(」と「)」で囲んだ間の条件にマッチする文字列を後に「\n」で参照できるという代物です。ここでいう「n」は数値となっていまして、最初の「( )」の内容は「\1」、次の「( )」の内容は「\2」で参照でき、「(」が登場した順番にその中身を参照できます。この「( )」は、入れ子表現も可能です。

しかし、今回成功したのは、あらかじめ表が「3×3」とわかっていたためです。「3×3」とわかっているからこそ、「^([^,]+),(.+),([^,]+)$」このような検索の仕方ができたのです。このプログラムをどんな表にでも使用するためにはどうすればよいのでしょう。次は汎用プログラムにチャレンジします。

できませんでした(´・ω・`)

一行で表せて、何列の表でも作れる正規表現がわかり、なおかつ管理人の道楽に付き合ってくれる方、お手数ですが管理人まで教えてください。

次にチャレンジするのは、HTMLタグ一括除去正規表現です。もう多分レベル5くらいになってますので、これはできそうな気がします。早速実験。ちなみに今回使うHTML文書のサンプルは以下のものです。

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html lang="ja">
<head>
<title>Perl(正規表現実験室)</title>
<META http-equiv="Content-Type" content="text/html; charset=Shift_JIS">
<META NAME="ROBOTS" CONTENT="ALL">
<link href="https://www.7key.jp/style.css" rel="stylesheet">
<style type="text/css">
<!--
	FONT.X {color: #ff0000;}
-->
</style>
</head>
<body bgcolor="#000000" text="#0066ff">
<p>
ここが内容
</p>
</body>
</html>
my($htmlFile) = './test.html';
open(HTML, "$htmlFile") || exit(0);
while(<HTML>){
   s/<\/?[^<]+>//g;
   print;
}
close(HTML);
exit(0);
結果>



Perl(正規表現実験室)




<!--
        FONT.X {color: #ff0000;}
-->




ここが内容



まずまず満足な結果が得られました。「<」で始まり、その次に「/」が1回あるか無いかどちらかで、「<」以外の一つ以上の文字の後に「>」がくるものを消去しなさい、といった指定になっています。あら…ということは、「<[^<]+>」の表現でもよかったですね。後はコメントタグや改行を除いてやれば実用レベルに到達するでしょう。できるとわかったので次の実験にいきます。

次は、「URL」ならば、「<a href="URL">URL</a>」と置換する正規表現にチャレンジしてみます。早速実験。

my($samp) = 'https://www.7key.jp/';
$samp =~ s/((http|ftp):[0-9a-zA-Z\.\$,;:&=\?!\*~@#_\(\)\/]+)/
          <a href=\"\1\">\1<\/a>/g;
print "$samp";
exit(0);
結果>
<a href="https://www.7key.jp/">https://www.7key.jp/</a>

かっこ悪いですが成功しました。URLに使用できる文字は、半角英数字及び、半角の以下の記号らしいです。「.」「$」「,」「;」「:」「&」「=」「?」「!」「*」「~」「@」「#」「_」「(」「)」補足としまして、他の立派な正規表現使いの方がかかれていましたサンプルを紹介しておきます。

$_ =~ s/([^=^\"]|^)((http|ftp):[!#-9\?=A-~]+)/$1<a href=$2 target=_top>$2<\/a>/g;

「[!#-9\?=A-~]+」この部分が随分シンプルですね。これでおそらく全文字を網羅してるのでしょう。

実験室3へ続くかも