Perl io layer

1,382 views

Published on

  • Be the first to comment

Perl io layer

  1. 1. Perl I/O Layer~ワイド文字のモダンな扱い方~ 2011/06/13 presented by : @yokomotod
  2. 2. 内部表現にデコードしてから処理する内部表現からエンコードして出力する 以上。 ね、簡単でしょう?
  3. 3. 内部表現?
  4. 4. 内部表現= Perlが文字列を処理するときに 内部で使っている表現→ Perlは“文字”として認識できる
  5. 5. 「Hello」という文字列はデータとしては「0011010111011101010101・・・」16進数だと「0x48 0x65 0x6c 0x6c 0x6f」アスキーコードの対応表で’a’ = ‘0x48’ とか決まってるから、「Hello」だと理解できる
  6. 6. ASCIIが世界のすべてだったらこれで終わり
  7. 7. しかし現実にはUTF-8EUC-JPSHIFT-JISLATIN-1・・・ ワイド文字ェ・・・
  8. 8. 問 「0x66 0x87 0x4e 0xba 0x30 0x81」 を文字列に直せ
  9. 9. Perl「無理ッス。(文字コード何だよ・・・)」
  10. 10. Perl「仕方ないからそのままにしておこう」$str =‘0x66’, ‘0x87’, ‘0x4e’, ‘0xba’, ‘0x30’, ‘0x81’ Not 内部表現 バイナリ文字列、って呼ぶんだったような
  11. 11. $str = 時間‘0x66’, ‘0x87’, ‘0x4e’, ‘0xba’, ‘0x30’, ‘0x81’ がな かっ たのprint lenght($str); #=> 6 で未print substr($str, 0, 3); 検証 !#=> ‘0x66’, ‘0x87’, ‘0x43’  文字化け !正規表現が複数バイト文字の一部分だけとマッチしたり境界をまたいだり
  12. 12. 文字コードを教えましょう
  13. 13. use Encode;$decoded_str = decode(‘utf-8’, $str);Perl「おk、utf-8な」
  14. 14. 結局、内部表現って?文字列を文字列として認識したPerlが、内部でデータを保存しておく表現。
  15. 15. とはいえ、独自に特殊な保存形式を使っている とかではなくただ単にutf-8に変換して保持しているだけなので、内部表現に変換した文字列のことを utf8フラグがついている文字列、とも呼びます
  16. 16. た だ し
  17. 17. utf-8 の文字列を入力するなら変換しなくていいということではない。utf8だろうがeuc-jpだろうが、きちんと文字コードを伝えてあげないと、Perlにとってはどちらも謎の数字列
  18. 18. さらに注意
  19. 19. 内部表現は直接出力してはいけない。
  20. 20. wide character in printというエラーに見覚えは?
  21. 21. 内部表現は、あくまでPerl内部で扱う形式端末がeuc-jp なら euc-jp を出してくれないと文字化けるそのまま出すのはオカシイ  だから警告
  22. 22. 実は内部表現はutf-8に過ぎないので、端末がutf-8なら、そのまま出しても化けないだ が し か しきちんと変換するのが正しいマナー
  23. 23. 例えばutf-8に変換するならuse Encode;print encode(‘utf-8’, $decoded_content);
  24. 24. ちなみにPerlが理解できる形式に変換するからdecodePerlがわからない形式に変換するからencode
  25. 25. 小休止。
  26. 26. どうやって内部表現に変換するか(=どうやって文字コードを伝えるか)
  27. 27. 基本中の基本Encode.pm を使うdecode(‘utf-8’, $str);encode(‘utf-8’, $decoded_str);
  28. 28. いちいち変換しないといけないのか? そんな仕様で大丈夫か?open my $fh, ‘<‘, $filename or die $!;while (<$fh>) { $line = decode(‘utf-8’, $_); chomp $line; my ($id, $title) = split /¥t/, $line; … print encode(‘utf-8’, $decoded_str). “¥n”;}close $fh;
  29. 29. 大丈夫だ。問題ない。
  30. 30. open my $fh, ‘<:utf8’, $filename;とすれば、読みだすデータに自動で decode(‘utf8’, $str)
  31. 31. binmode STDOUT, ‘:utf8’;と書くと、標準出力にprintするときに、自動的に encode(‘utf8’, $str)
  32. 32. binmode STDOUT, ‘:utf8’;open my $fh, ‘<:utf8‘, $filename or die $!;while (<$fh>) { chomp $line; my ($id, $title) = split /¥t/, $line; … print $decoded_str. “¥n”;}close $fh;
  33. 33. ソースコードに文字列を書くときも注意if ($str =~ /牧田/ && $str =~ /かっこいい/) { # do something}else { die “error !”;}
  34. 34. ソースコードの文字コードも、Perlは知りません。
  35. 35. use utf8;としてやると、ソースコードがutf8で書かれていると認識されて、ソース中の文字列が内部表現として認識される当然、ソースコードはutf8で書くこと。
  36. 36. 他には?
  37. 37. Perlへの入出力の整理入力 ファイル/ソースコード/MySQL/LWP出力 画面/ファイル/MySQL
  38. 38. ファイル open my $fh, ‘<:utf8’, $filename; open my $out, ‘>:utf8’, $filename;画面 binmode STDOUT, ‘:utf8’;ソースコード use utf8;
  39. 39. MySQLmy $dbh = DBI->connect( ‘dbi:mysql:database’, ‘user’, ‘passwd’, { mysql_enable_utf8 => 1, } ) or die $!;
  40. 40. データベース側のカラム設定がutf8文字になっていれば、自動で内部表現との変換をやってくれる(SELECTもINSERTも)もしかしたら、binaryじゃなければいいかも?僕は知りません。MySQLの文字コードをutf8以外にしたことなんてないので。
  41. 41. LWP::UserAgentmy $res = LWP::UserAgent->get(…)my $content = $res->decoded_content
  42. 42. まぁ忘れたら encode / decode で
  43. 43. ちなみにutf-8 に encode / decode するときはencode(‘utf8’, $str) としなくてもencode_utf8($str) というのがあるタイピングを2文字節約できるよ!
  44. 44. 内部表現をマスターすれば
  45. 45. my $str = ‘今日はPerlのライトニングトーク。’;length($str) #=> 19substr(‘$str’, 0, 3) #=> ‘今日は’$str =~ s/。/; #=> ‘‘今日はPerlのライトニングトーク’split(//, $str) #=> (今 日 は P e r l のラ イ ト ニ ン ク ゙ ト ー ク 。)
  46. 46. Enjoy wide character !See AlsoEncodeでラクラク日本語処理 - JPerl Advent Calendar 2009 http://perl-users.jp/articles/advent-calendar/2009/casual/10.html

×