« C#:万華鏡丸形 - Kaleidoscope Round | トップページ | 東京凰籃学院のオリジナル練習問題が良質すぎる件 »

2015年10月28日 (水)

PerlでShiftjisのファイルを文字化けさせずに操作する

ShiftjisでPerlスクリプトを書きShiftjisのファイルを読み込むとよく文字化けする。

これは、いわゆるダメ文字(2バイト目がPerlの制御文字と同じコード)のせいである。

Perlスクリプトと読み込むファイルをともにutf8にすれば万事解決するのであるが、なかなかそうもいかない人が多いらしい。

理由は簡単で、Windowsで作成した文書のほとんどがShiftjisだからだ。それらをすべてutf8に変更するのは非常に骨が折れる。

Shiftjisの世界では文字化けを回避する方法はないとされるが、とりあえずPerlスクリプトだけでもutf8にすることで応急処置ができそうなので試してみた。

まず、問題の再現。

ダメ文字を満載した以下のHTMLファイルを用意。

sjisperl.html(Shiftjisで書かれている)

<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=shift_jis">
</head>
<body style="font-family:monospace;font-size:12px">
<p>平成二七年度氷芋掘り大会</p>
<p>参加費 \3500</p>
<p>ァА①院魁機掘后察宗拭繊叩邸如鼻法諭蓮僉咫奸廖戞曄檗漾瓠磧紂隋蕁襦蹇錙顱鵝纊犾</p>
<p>ーゼЪⅧ閏骸擬啓梗纂充深措端甜納票房夕麓兌喙媼彈拏杣歇濕畆禺綣膽藜觴躰鐚饉鷦倞劯</p>
<p>―ソЫⅨ噂浬欺圭構蚕十申曾箪貼能表暴予禄兔喀媾彌拿杤歃濬畚秉綵臀藹觸軆鐔饅鷭偆砡</p>
<p>‐ゾЬⅩ云馨犠珪江讃従疹曽綻転脳評望余肋兢咯嫋彎拆枉歉濔畩秕緇臂蘊訃躱鐓饐鷯偰硎</p>
<p>/タЭ運蛙疑型洪賛戎真楚耽顛膿豹某与録竸喊嫂弯擔杰歐濘畤秧綽膺蘓訖躾鐃饋鷽偂硤</p>
<p>\ダЮ㍉雲垣祇契浩酸柔神狙胆点農廟棒誉論兩喟媽彑拈枩歙濱畧秬綫臉蘋訐軅鐇饑鸚傔硺</p>
<p>AチЯ㌔荏柿義形港餐汁秦疏蛋伝覗描冒輿倭兪啻嫣彖拜杼歔濮畫秡總臍藾訌軈鐐饒鸛僴礰</p>
<p>+ボк閲顎宮鶏砿施旬須捜畜怒倍府本養几嘴學悳掉桀毬炮痣窖縵艝蛔諚轆閔驅黠垬葈</p>
<p>-ポл榎掛弓芸鋼旨楯酢掃竹倒培怖翻慾處嘶斈忿掟桍毫烟痞窩縹艚蛞諫轎閖驂黥埈蒴</p>
<p>±マм厭笠急迎閤枝殉図挿筑党媒扶凡抑凩嘲孺怡掵栲毳烋痾竈繃艟蛩諳轗閘驀黨埇蕓</p>
<p>×ミн㍻円樫救鯨降止淳厨掻蓄冬梅敷盆欲凭嘸宀恠捫桎毯烝痿窰縷艤蛬諧轜閙驃黯﨏蕙</p>
<p>参加申込は icepotato@ice.po.ta.to まで。(メアドの@は半角にして)</p>
</body>
</html>

これをShiftjisで書かれた次のPerlスクリプトで、主として半角記号を置き換えるという、過酷な置換操作を行ってみる。

sjisPerlDirect.cgi(Shiftjisで書かれている)

#! /usr/bin/perl
use Encode;

print "Content-type: text/html;charset=shift_jis\n\n";

open IN, "sjisperl.html";

foreach(<IN>){
    s/二七/二八/g;
    s/\@/@/g;
    s/\[/[/g;
    s/\\/¥/g;
    s/\]/]/g;
    s/\^/^/g;
    s/\_/\-/g;
    s/\`/`/g;
    s/\{/{/g;
    s/\|/|/g;
    s/\}/}/g;
    s/\~/~/g;
    print "$_\n";
}

close IN;

exit;

__END__

と、もちろんこうなる。

Sjisperl1_2

問題は再現できた。というか酷すぎる。特に、スクリプト内に s/表/裏/; のようにダメ文字を記述することすらエラーの原因になる。

そこで、Perlスクリプトだけでもutf8で保存し、以下の黄色い字の部分を追加する。さらにShiftjisではできないはずのダメ文字の置換(赤い字)も追加。

sjisPerlOnUtf8.cgi(utf8 no signatureで書かれている)

#! /usr/bin/perl
use utf8;
use Encode;


print "Content-type: text/html;charset=shift_jis\n\n";

open IN, "sjisperl.html";

foreach(<IN>){
    $_ = decode('CP932', $_);
    s/\r|\n//g;
    s/二七/二八/g;
    s/表/裏/g;
    s/申/申(さる)/g;
    s/Ⅸ/Ⅸ(9)/g;
    s/㌔/㌔(きろ)/g;
    s/\@/@/g;
    s/\[/[/g;
    s/\\/¥/g;
    s/\]/]/g;
    s/\^/^/g;
    s/\_/\-/g;
    s/\`/`/g;
    s/\{/{/g;
    s/\|/|/g;
    s/\}/}/g;
    s/\~/~/g;
    $_ = encode('CP932', $_);
    print "$_\n";
}

close IN;

exit;

__END__

すると次のように全く文字化けは起きず、置換操作(青丸の部分)もすべてうまくいっている。

Sjisperl2_3

やっていることは以下の通り。

  1. Shiftjisのファイルを読み込む際にCP932として扱ってPerlの内部文字列にデコード
  2. 好きなように料理
  3. 書き出すときにCP932としてエンコード。

これでShiftjisの膨大なファイル資源を当面は再利用できそうだ。

 

 

« C#:万華鏡丸形 - Kaleidoscope Round | トップページ | 東京凰籃学院のオリジナル練習問題が良質すぎる件 »

2018年10月
  1 2 3 4 5 6
7 8 9 10 11 12 13
14 15 16 17 18 19 20
21 22 23 24 25 26 27
28 29 30 31      

ブックマーク

無料ブログはココログ