キーワード

プロフィール

深沢千尋

Author:深沢千尋
みなさんこんにちは、深沢千尋です。(公式ページ
文字コード【超】研究 改訂第2版NEW!」「すぐわかるPerl」「すぐわかる オブジェクト指向 Perl」の著者です。
ここでは、多くは技術的でないこと、ごくまれに技術的なことをなげやりに書いていきます。
メールは suguwakaruPerl@gmail.com まで。(アットマークは ASCII に)
Twitterはじめました。@query1000です。よろしく~

最新記事

最新コメント

最新トラックバック

月別アーカイブ

カテゴリ

検索フォーム

RSSリンクの表示

リンク

ブロとも申請フォーム

QRコード

QRコード

スポンサーサイト

上記の広告は1ヶ月以上更新のないブログに表示されています。
新しい記事を書く事で広告が消せます。

「まるごとEncode」解題(1)Encode以前のPerl(を説明するプログラムのはずが・・・)

2006年9月インプレス刊『まるごとPerl』の中の小飼 弾氏の記事「まるごとEncode」のコードを打ち込んで勉強しました。
以下に勉強の内容を書きます。
コードの内容は変えて、注釈も足してあります。
Dan さんの原記事や、この本全体は大変面白いので、ぜひそちらもお読みください。




かつての Perl は情報をオクテット単位で処理していたので、substr などの関数は、abcABC などの ASCII 文字は1文字ずつ処理していたが、「あいうえお」などのマルチバイト文字は、Shift_JIS の場合は半文字ずつ処理したり、UTF-8 の場合は 1/3 文字ずつ処理したりしていた。

#! perl
# oldPerl.pl -- かつてのPerl同様に、1オクテットを1文字として解釈
# UTF-8で保存して実行すること

use strict;
use warnings;
use Encode;

binmode STDOUT, ':encoding(cp932)'; # 出力はCP932に変更

# use utf8; と書いていないので、オクテット単位で解釈される

my $text = 'abc漢字ひらがなカタカナ';

# UTF-8 だから「abc漢字」9オクテット使う

# decode して UTF-8 にしてやる
print decode('utf8', substr($text, 9, 12));

__END__

上のコードを実行すると以下のようになる。

C:\Documents and Settings\you\デスクトップ\Marugoto>oldPerl.pl
ひらがな



原記事は(おそらく UNIX 環境で)UTF-8 対応端末で実行するように書かれていたが、これを Strawberry Perl 5.10.1+Windows XP+コマンドプロンプト(以降は DOS 窓と呼ぶ)で実行した。
DOS 窓でも chcp 65001 で UTF-8 が表示されるはずだが、日本語を表示するためにレジストリをいじらなければならなく、ヘンな文字化けがいつまでたっても治らない。

上の Perl は、昔(5.5 時代)の Perl では文字列はオクテット単位だったんだよということを示すためのものだが、それを DOS 窓で表示するためにいろいろ新しい命令を使っている。

まず、

binmode STDOUT, ':encoding(cp932)'; # 出力はCP932に変更

で標準出力に出て行く文字コードを CP932 に切り替えている。
binmode は昔は Windows 用の Perl の改行モードを ASCII モードか Binary モードか切り替えていた。
最近の Perl(>= 5.6)では上のように文字コード系を指定できる。

あと、

print decode('utf8', substr($text, 9, 12));

も原記事では普通に

print substr($text, 9, 12);

だったが、こうすると

"\x{0081}" does not map to cp932.
"\x{0082}" does not map to cp932.
"\x{0089}" does not map to cp932.
"\x{0081}" does not map to cp932.
"\x{008c}" does not map to cp932.
"\x{0081}" does not map to cp932.
a\x{0081}2a\x{0082}\x{0089}a\x{0081}\x{008c}a\x{0081}a

となる。
出力された文字列を見ると、

a
\x{0081}
2
a
\x{0082}
\x{0089}
a
\x{0081}
\x{008c}
a
\x{0081}
a

と、12 文字/12 オクテットある。
これは、このスクリプトが use utf8; していないので ISO 8859-1 として解釈されていることがわかる。
(\x{0081}~\x{008c} は ISO 8859-1 にないので cp932 に変換できなくて怒られた)

binmode はこの文字を encode(Perl の内部表現からバイトストリームに変換)してから指定された文字コード系(ここでは cp932)に変換しようとする。
しかし、encode するためには文字列が Perl の内部表現でなければいけないので、decode を行う。

Perl の内部表現とは「文字列を文字列として扱うための特別な表現」である。
(実際には UTF8 フラグが立った UTF-8 列である。ただし、プログラマーが「UTF-8 であること」「UTF8 フラグが立ったり座ったりする」ことを意識することは推奨されていない。)

それに対してバイトストリームとはプログラムの外から入ってくるバイトの列である。

外界から入ってきたデータは decode して内部表現に変換し、内部表現を外界に出すためには encode してバイトストリームに変換する。

しかし、上のプログラムは use utf8; が書かれていないので、プログラムのリテラル文字列がバイトストリームである。
ところが、binmode を指定したファイルハンドル(ここでは STDOUT)への print を行うと、自動的に encode が行われる。
よって、その前に decode しておかなければならなかったわけである。

なお、

print decode('utf8', substr($text, 9, 12));

という風に書いているが、decode は Encode モジュールのメソッドであって、Perl の組み込み関数ではない。
これを使うために

use Encode;

を書いている。

・内部表現/バイトストリーム
・use utf8
・binmode
・decode/encode

以上の内容は、原記事ではこれ以降に順を追って出てくるが、上では DOS 窓で実行するために結局これらをすべて習得する羽目になってしまった。
スポンサーサイト

テーマ : 雑記 - ジャンル : その他

<< 「まるごとEncode」(2)use utf8の導入 | ホーム | [つぶやき]そうそう。ウィンクしてるのとそうじゃないのと大量にいる (^ >>


コメント

コメントの投稿


管理者にだけ表示を許可する

 ホーム 


上記広告は1ヶ月以上更新のないブログに表示されています。新しい記事を書くことで広告を消せます。