Cannot decode string with wide characters at ...

2010年12月9日に持ち込まれた謎

Windowsperlを動かす。

Encode::from_to($line, "shiftjis", "utf8" );

の行で
Cannot decode string with wide characters at...
と怒られる。

$lineのUTF-8フラグが立っているのが悪いらしい。

$line_off = Encode::encode_utf8($line);

とすると、怒られなくなった。

Quantifier follows nothing in regex; marked by ...

2010年11月18日に持ち込まれた謎

Windowsperlを動かす。

if( $str =~ /$list[$i]/ ) {

の行で
Quantifier follows nothing in regex; marked by <-- HERE in m/? ...
と怒られる。

正規表現を量指定子で開始しています。もしそれをリテラルに使いたいなら、バックスラッシュでクォートしてください。 <-- HERE で正規表現のどこに問題が発見されたかを示しています。

だそうだ。
$list[$i]の中身が悪さしてるのねぇ。

quotemeta関数を使って解決。
英数字以外の文字をバックスラッシュでエスケープしてくれるらしい。

if( $str =~ /quotemeta($list[$i])/ ) {

そんなにエスケープしても大丈夫なのかな?と素朴な疑問。

Wide character in print at ...

2010年11月18日に持ち込まれた謎

Windowsperlを動かす。

  • piyopiyo.pl(utf-8
    • use Encode;
    • use utf8;
    • use open IN => ":utf8";
    • binmode STDOUT, ":encoding(cp932)";
  • bbb.txt(Shift_JIS
    • はじめまして。
    • はじめません。
    • はじらいます。
    • …みたいな日本語文がぞろぞろ入ってる。


piyopiyo.plでbbb.txtを読み込み、いろいろやってからファイルにShift_JISで書き出したいだけ。
ただそれだけ。

"いろいろやる"の部分にマッチングとかもあるので、最初にUTF-8にしとく。

open(IN, "bbb.txt") or die "$!"; #これはshiftjis
while ( $line = ) {
Encode::from_to($line, "shiftjis", "utf8");

#ごにょごにょしてから書き出す

}
close(IN);

さて、Shift_JISに戻してファイルに書き出すぞ〜と思ったら…

Wide character in print at ...

よくみるあいつです。
別に問題ないんけど、標準出力にいろいろ出したかったので、だだだーっとあいつが現れると困る。

UTF8フラグを落としてしまおう。

"\x{0081}" does not map to cp932 at ...

UTF8フラグは落とせるけど、おもわしくない事態に。
じゃあ$lineをShift-JISにしちゃおう、と思ったらどうやってもできない。

最終的に落ち着いた解決策は、ファイルをopenするときに文字コードを指定してしまおうというやつ。

open (OUT, ">:encoding(shiftjis)","ccc.txt") or die "$!";

いまいちすっきりしない!

見えざる敵BOM

2010年11月15日に持ち込まれた謎

Windowsperlを動かす。

  • aaa.pl(utf-8
    • use Encode;
    • use utf8;
    • use open IN => ":utf8";
    • binmode STDOUT, ":encoding(cp932)";
  • bbb.txt(utf-8
    • はじめまして。
    • はじめません。
    • はじらいます。
    • …みたいな日本語文がぞろぞろ入ってる。


aaa.plでbbb.txtを読み込み、配列@cccに格納。
@cccの中身を見てみよう。

print $ccc[0];
print $ccc[0];
print $ccc[1];

はじめまして。
?はじめまして。
はじめません。

むむむ…?
1行目の頭に何かくっついてる…?

print substr ($ccc[0], 0, 1);

"\x{feff}" does not map to cp932.
\x{feff}

やっぱり何かある!!

試行錯誤して一応解決

"\x{feff}"でぐぐってみた結果、utf-8のファイルの先頭にはBOM(Byte Order Mark)ってのがつくことがあるらしい。
utf-8NBOMなしってことを初めて知った。
今回初めてこの事件が起こったのは、Windowsのメモ帳で開いたのが原因かも。

TeraPadutf-8Nに変換したら解決した。

$ccc[0] = substr ($ccc[0], 1, length($ccc[0]));

↑みたいに強引にBOMをちぎってもうまくいってた気がする。