改行騒動

昔のファイルの整理をしていると、「# ★これがなぜ表示されないのか」というコメントが目についた。確かに、今実行してみるとやはり表示されない。このまま整理しても意味はないので考え込んでしまう。


問題の部分

次のようなeuc-jpで書かれたテキストがある(euc.txt)。行末の改行はLF(0x0a)である。
SAMPLE
篠崎愛
本田美穂
有村架純
高畑充希

プログラミング my $filename="euc.txt"; my @ary; my $tmp; my $str; open FILE, "<$filename"; @ary = <FILE>; close(FILE); foreach $line (@ary) { $tmp = $line . "<br>"; $str .= $tmp; } print "<script>\n"; print "document.write(\"$str\")\n"; # ★これがなぜ表示されないのか。 print "</script>\n";


原因はどこに

こういうのに出会うとすぐに考え込んでしまって、「横道」にそれてしまうのである。それでいつまでたっても整理が進まない。しかし、未解決のまま整理してもあまり意味がない。この際に考えておくか。Perl/CGIに問題があるのか、それともJavaScriptに問題があるのか。
これを次のようにすると想定した形で表示される。

プログラミング my $filename="euc.txt"; my @ary; my $tmp; my $str; open FILE, "<$filename"; @ary = <FILE>; close(FILE); foreach $line (@ary) { $tmp = $line . "<br>"; $str .= $tmp; } print $str;

この実行結果の「ソース」を見ると次のようになっている(文字化けは修正)。
SAMPLE
篠崎愛
<br>本田美穂
<br>有村架純
<br>高畑充希

元のテキストの各行の末尾に「LF(0x0a)」が付いているが、それがそのまま配列(@ary)に取り込まれている。
こちらが明示的に入れた「<br>」が改行後の先頭に付いていることでも、それがわかる。このこと自体は当然のことである。

これを次のように少し変えてみる。

プログラミング foreach $line (@ary) { chomp($line); # 各行の末尾の改行(LF)を取り去る。 $tmp = $line . "<br>"; $str .= $tmp; } print $str;

この実行結果の「ソース」を見ると次のようになっている(文字化けは修正)。
SAMPLE
篠崎愛<br>本田美穂<br>有村架純<br>高畑充希

この両者はブラウザで表示すると両方とも次のように見える。
SAMPLE
篠崎愛
本田美穂
有村架純
高畑充希

外観上の差はない。ここが盲点になってしまう。外観は同じでも、それぞれのデータには質的な相違があるということを忘れてしまうのである。

この典型的な例がCSVファイルの処理であろう。各行単位でテキストを取得して、カンマ(,)でデータを切り分けたとき、最後のデータには改行がついてしまうことになり、そのままでは正常な処理ができなくなる。こういうことは今まで何度も経験してきたことである。


document.writeの問題点

しかし、そういう貴重な体験も、場面がちょっと変わると、もうコロッと忘れてしまう。げに、「人間は忘れる動物である」ことよ(笑)。冒頭の例でも、理論的には同じテキストが表示されるはずだが、、、そうにはならない。

なぜ何も表示されないのか。これにハタと考えこんでしまうのである。

ところで、document.writeは1行テキストの表示に限られる(ようである)。
これは次の例からも確認できる。引数が1行の場合。
SAMPLE
<script>
document.write("篠崎愛<br>本田美穂<br>");
</script>

↓これは表示される。

これを2行に分けるとどうなるか。引数が2行の場合。
SAMPLE
<script>
document.write("篠崎愛<br>
本田美穂<br>");
</script>

↓これは表示されない。

ということは、冒頭の例ではデータを連結して一つの文字列にした $str の中に改行コード(0x0a)が混入していて、複数行のテキストになっていたということである。このことをコロッと忘れていたのである。

プログラミング print "<script>\n"; print "document.write(\"$str\")\n"; # ★これがなぜ表示されないのか。 # $strは複数行のデータになっていたからである。 print "</script>\n";

結局、この問題の原因はCGIではなく、JavaScriptのdocument.writeのほうにあったということである。
document.writeは1行テキストの表示に限られる。
したがって、元のテキストの各行の末尾には改行(LF)が付いている。その行末の改行を取る「chop($line);」または「chomp($line);」を入れればすむだけの話だったのである。そうすればJavaScriptでも想定通りの表示がなされることになる。これにて一件落着(笑)。

- 2019/08/24 -