blog20100901

2013/08/20 - プログラミング言語 Perl にまつわる etc. - Perl monger
参考 : perldoc, perldoc.jp, search.cpan.org, perldoc.perl.org ...
「 初めての Perl 第 6 版 」(オライリー・ジャパン発行 ISBN978-4-87311-567-2) 」
「 続・初めての Perl 改訂版 」(オライリー・ジャパン発行 ISBN4-87311-305-9) 」
「 Effective Perl 第 2 版 」(翔泳社発行 ISBN978-4-7981-3981-4) 」 ... etc,.

Perl Perl_4

Perl 日本語文字列の扱い encode /decode, flagged utf8, EUC-JP (0x244)

Perl 日本語文字列の扱い encode /decode, flagged utf8, EUC-JP (0x244)

目次 - Perl Index



Theme



Perl について、復習を兼ねて断片的な情報を掲載して行く連載その 0x244 回。

Perl で、文字列の中から「 部分文字列 」の最初の位置を返す関数「 index 」や「 正規表現 」のマッチングを利用して「 日本語文字列 」( マルチバイト文字列 ) の入出力の基本を再確認する。



マルチバイト文字列の処理の心得



心得。

入り口で decode して、内部ではすべて flagged utf8 で扱い、出口で encode する。これがすべてです!とにかくこの基本方針をまもっていれば幸せになれます。
Perl で utf8 化けしたときにどうしたらいいか - tokuhirom's blog


外部から入力された文字列を処理して出力する



外部からの入力により受け付けた文字列を、プログラム内で関数「 index 」(0x243) を利用して処理し、その結果を外部に出力するプログラムコードを書きました。プログラムファイルの文字コードは「 UTF-8 」です。


#!/usr/bin/perl

use strict;
use warnings;

# 文字列リテラルを flagged utf8 として扱うプラグマ
use utf8;

# デコード/エンコード のためのモジュール
use Encode;

my $string;
my $substr;

# (1) 外部から文字列を受け付ける
until( $string && $substr ) {

unless ($string) {
print "Please enter any string: ";
print "Already set substr to '$substr'\n: " if ($substr);
chomp($string = <STDIN>);
}
unless ($substr) {
print "substring ";
print "for '$string'\n: " if $string;
chomp($substr = <STDIN>);
}
}

# (2) 文字列を処理する前に flagged utf8 に変換 (デコード)
my $dec_string = decode('utf-8', $string);
my $dec_substr = decode('utf-8', $substr);

# (3) flagged utf8 にデコードした文字列を処理
my $where = index($dec_string, $dec_substr);

# (4) 出力する前に flagged utf8 を UTF-8 に変換 (エンコード)
my $enc_substr = encode('utf-8', $dec_substr);

# (5) UTF-8 に変換した文字列を出力
print "$enc_substr position: $where\n\n";




基本的な流れは、これで問題ないと理解しています。


マルチバイトの文字列リテラル (use utf8)



前項のプログラムコードにはマルチバイトの「 文字列リテラル 」が含まれません。

マルチバイトの「 文字列リテラル 」を含んでいて、かつ、「 use uft8 」を指定しているプログラムコードでは、「 文字列リテラル 」がはじめから「 flagged utf8 」として扱われます。

ですから、次のような文字列マッチングも正しく機能します。


use utf8;
use Encode;

print "please enter string: ";
chomp(my $str = <STDIN>);

# 外部からの入力は flagged utf8 にデコードする
my $dec_str = decode('utf-8', $str);

# use utf8 では文字列リテラルをそのままマッチング可能
if ($dec_str =~ /ワールド/) {

# 出力時には任意の文字コードにエンコードする
print encode('utf-8',"'$dec_str' には [ワールド] が含まれます。"),"\n";
} else {
print encode('utf-8',"'$dec_str' には [ワールド] が含まれません。"),"\n";
}



外部に出力する場合は、「 flagged utf8 ( 内部文字列 ) 」から任意の文字コード ( ここでは UTF-8 ) にエンコードしておく必要があります。

そうでなければ、マルチバイトの文字列は「 flagged utf8 」のまま出力されるので、警告メッセージ「 Wide character in print at ... 」が併せて出力されてしまいます。


マルチバイトの文字列リテラル (no utf8)



マルチバイトの「 文字列リテラル 」を含むプログラムコードで、「 use utf8 」を利用していない場合は、エンコード / デコード をすることなく正規表現によるマッチングや出力が可能です。


#use utf8;
#use Encode;

print "please enter string: ";
chomp(my $str = <STDIN>);

my $dec_str = $str;

if ($dec_str =~ /ワールド/) {
print "'$dec_str' には [ワールド] が含まれます。\n";
} else {
print "'$dec_str' には [ワールド] が含まれません。\n";
}



しかしながら、正規表現はどうなる? (perl - use utf8; #って何だ?) - 404 Blog Not Found で言及されている様に、「 flagged utf8 」を利用しない場合は、意図していない正規表現マッチング等の問題が発生する可能性があります。

このため、通常は「 use utf8 」を指定しつつ、冒頭の心得「 入り口で decode して、内部の処理は flagged utf8 で行い、出口で encode する。」を元にして処理を書いた方がよさそうです。もちろんプログラムファイルの文字コードは「 UTF-8 」です。


EUC-JP でプログラムコードを書く場合



2015 年現在でも、システムの文字コードが「 EUC-JP 」になっている環境は少なくないかと思います (少し前の FreeBSD 等)。

システムの環境に併せてプログラムコードを「 EUC-JP 」で書く場合は、おそらく utf8 - perldoc.jp に書かれている通り「 use utf8 」は指定してはいけません ( エラーにはなりませんが エンコード / デコード がややこしいことになります )。

「 use utf8 」を指定しないということは、通常文字列の エンコード / デコード 処理を行わずとも問題はないはずですが、「 心得 」に従って次のように書いてみました。


use Encode;

print "please enter string: ";
chomp(my $str = <STDIN>);

# 入力された文字列を flagged utf8 にデコード
my $dec_str = decode('euc-jp', $str);

# リテラルも flagged utf8 にデコード
my $patn = decode('euc-jp', 'ワールド');

# flagged utf8 同士でマッチング ( 安心 )
if ($dec_str =~ /$patn/ ) {

# 出力する場合は任意の文字コードにエンコード
print encode('euc-jp', $dec_str), " には [ワールド] が含まれます。\n";

} else {

# 出力する場合は任意の文字コードにエンコード
print encode('euc-jp',$dec_str), " には [ワールド] が含まれません。\n";

}



システムの環境が「 EUC-JP 」でも、プログラムファイルを「 UTF-8 」で書くことが出来ます。

プログラムファイルの文字コードが「 UTF-8 」であれば、「 use utf8 」を利用することが出来ますが、環境が「 EUC-JP 」なので、入出力時の デコード / エンコード は「 EUC-JP 」を指定しました。


# リテラルを flagged utf8 で扱う
use utf8;
use Encode;

print "please enter string: ";
chomp(my $str = <STDIN>);

# flagged utf8
my $dec_str = decode('euc-jp', $str);

# flagged utf8 同士でマッチング ( 安心 )
if ($dec_str =~ /ワールド/) {

# 環境に併せて EUC-JP にエンコードして出力
print encode('euc-jp', "$dec_str には [ワールド] が含まれます。"), "\n";

} else {

# 環境に併せて EUC-JP にエンコードして出力
print encode('euc-jp',$dec_str には [ワールド] が含まれません。"), "\n";

}




0x244 -> 0x245 へ



僕の環境は少し前まで EUC-JP な FreeBSD 8 と 9 が中心だったので、環境に合わせてプログラムファイルは EUC-JP で書いていました。

その頃の僕は「 use utf8 」を「 EUC-JP 」なプログラムファイルで指定してはいけないことを知らなかったので、マルチバイト文字列の処理でいつも何かが引っかかっていました。

経験則的に「 use utf8 」を外せばうまくいくのは分かるようになったのですが、大抵の場合「 日本語処理には use utf8 を利用する 」と書いてあるのに、なぜ僕の環境ではうまくいかないのかが理解できませんでした。

はじめから UTF-8 な環境で UTF-8 なプログラムファイルを使っていれば、こんなことにはならなかったと思いますが、おかげで良い勉強ができたと思うようにしています。


次回は、 部分文字列の置換と抽出が出来る関数「 substr 」を確認します。


参考情報は書籍「 初めての Perl 第 6 版 」を中心に perldoc, Wikipedia および各 Web サイト。それと詳しい先輩。

目次 - Perl Index






















同じカテゴリー(Perl)の記事
 Perl mp2 翻訳 Web コンテンツ圧縮の FAQ (d228) (2023-10-11 23:49)
 Perl mp2 翻訳 既知のブラウザのバグの回避策をいくつか (d227) (2023-05-26 15:41)
 Perl mp2 翻訳 Perl と Apache でのキュートなトリック (d226) (2023-05-19 17:05)
 Perl mp2 翻訳 テンプレートシステムの選択 (d225) (2022-08-15 22:23)
 Perl mp2 翻訳 大規模 E コマースサイトの構築 (d224) (2022-06-15 20:43)
 Perl mp2 翻訳 チュートリアル (d223) (2022-06-15 20:42)
上の画像に書かれている文字を入力して下さい
 
<ご注意>
書き込まれた内容は公開され、ブログの持ち主だけが削除できます。

Llama
リャマ
TI-DA
てぃーだブログ
プロフィール
セラ (perlackline)
セラ (perlackline)
QRコード
QRCODE
オーナーへメッセージ

PAGE TOP ▲