rubyのエンコーディング
Post on 26-Jun-2015
13.445 Views
Preview:
TRANSCRIPT
Rubyのエンコーディング - NSEG#30 Powered by Rabbit 1.0.9
RubyのエンコーディングNSEG#30
とみたまさひろ2012-08-25
Rubyのエンコーディング - NSEG#30 Powered by Rabbit 1.0.9
自己紹介
とみた まさひろ (ペンネーム)✓
プログラマー (Ruby & C)✓
http://d.hatena.ne.jp/tmtms✓
http://twitter.com/tmtms✓
好きなもの
Ruby, MySQL, Ubuntu, Emacs, Git✓
✓
1/45
Rubyのエンコーディング - NSEG#30 Powered by Rabbit 1.0.9
NSEG#1 Rubyの黒魔術✓
#3 はじめてのRuby拡張ライブラリ✓
#6 Ruby紹介✓
#11 RSpecとCucumber✓
#13 システムコール✓
#14 MySQLの文字コード✓
#18 Rabbit✓
#20 TDDについて✓
#21 Linuxのメモリ✓ 2/45
Rubyのエンコーディング - NSEG#30 Powered by Rabbit 1.0.9
Ruby 1.8 は
オワコン3/45
Rubyのエンコーディング - NSEG#30 Powered by Rabbit 1.0.9
1.8.7の今後につきまして2012年6月まで、通常のメンテナンスが続きます。
✓
それ以降、バグフィックスリリースは終了いたします。2013年6月まではセキュリティフィックスは続けますので、それまでは1.8.7をお使いいただけます。
✓
2013年6月より先は、1.8.7はあらゆるサポート対象外になります。
✓
http://www.ruby-lang.org/ja/news/2011/10/07/plans-for-1-8-7/ 4/45
Rubyのエンコーディング - NSEG#30 Powered by Rabbit 1.0.9
Ruby 1.9 を使いまし
ょう5/45
Rubyのエンコーディング - NSEG#30 Powered by Rabbit 1.0.9
1.9の特徴
6/45
Rubyのエンコーディング - NSEG#30 Powered by Rabbit 1.0.9
一番大きいのはエンコーディング
7/45
Rubyのエンコーディング - NSEG#30 Powered by Rabbit 1.0.9
Rubyのエンコーディング
http://d.hatena.ne.jp/tmtms/20120812/ruby_encoding
8/45
Rubyのエンコーディング - NSEG#30 Powered by Rabbit 1.0.9
エンコーディング?
文字符号化方式✓
UTF-8 とか EUC-JP とか SHIFT_JIS とかそーゆー奴
✓
charset とか呼ばれたり✓
いわゆる「文字コード」✓
9/45
Rubyのエンコーディング - NSEG#30 Powered by Rabbit 1.0.9
同じ文字でも異なるコード
「あ」
UTF-8 では 0xE3 0x81 0x82 の3バイト✓
EUC-JP では 0xA4 0xA2 の2バイト✓
SHIFT_JIS では 0x82 0xA0 の2バイト✓
10/45
Rubyのエンコーディング - NSEG#30 Powered by Rabbit 1.0.9
同じバイト列でも別の文字
0xC2 0xA9 の2バイトは
UTF-8 では「©」1文字✓
EUC-JP では「息」1文字✓
SHIFT_JIS では「ツゥ」2文字✓
11/45
Rubyのエンコーディング - NSEG#30 Powered by Rabbit 1.0.9
Ruby 1.8.x
"\xC2\xA9" という文字列は Ruby 的にはただのバイト列
✓
エンコーディング情報を持たない✓
"©"(UTF-8) として扱うか "息"(EUC-JP) として扱うかはプログラム次第
✓
12/45
Rubyのエンコーディング - NSEG#30 Powered by Rabbit 1.0.9
Ruby 1.9.x
文字列のエンコーディングは文字列自身が知っている
✓
"©"(UTF-8) と "息"(EUC-JP) は同じバイト列だけど異なる文字列
✓
"あ"(UTF-8) と "あ"(EUC-JP) は同じ文字を表してるけど等しくない
✓
同じプログラム中で複数のエンコーディングの文字列を同時に扱える(珍しいかも)
✓
13/45
Rubyのエンコーディング - NSEG#30 Powered by Rabbit 1.0.9
ちゃんと文字として扱える
# Ruby 1.8.7"文字".size #=> 6"文字".bytesize #=> 6"文字"[0] #=> 230 (0xE6)"文字".reverse #=> "??????"
# Ruby 1.9.3"文字".size #=> 2"文字".bytesize #=> 6"文字"[0] #=> "文""文字".reverse #=> "字文"
14/45
Rubyのエンコーディング - NSEG#30 Powered by Rabbit 1.0.9
String#encoding
文字列のエンコーディングを調べる
"あ".encoding #=> #<Encoding:UTF-8>
15/45
Rubyのエンコーディング - NSEG#30 Powered by Rabbit 1.0.9
String#encode
エンコーディング変換
str = "あ"str.encoding #=> #<Encoding:UTF-8>str2 = str.encode("cp932")str2.encoding #=> #<Encoding:Windows-31J>
16/45
Rubyのエンコーディング - NSEG#30 Powered by Rabbit 1.0.9
エンコーディングは何で決まる?
スクリプトエンコーディング✓
外部エンコーディング✓
内部エンコーディング✓
17/45
Rubyのエンコーディング - NSEG#30 Powered by Rabbit 1.0.9
スクリプトエンコーディング
スクリプト中の文字列リテラルのエンコーディングを決定する
✓
スクリプト先頭行のマジックコメントで指定する
# coding: utf-8"あ".encoding #=> #<Encoding:UTF-8>
✓
デフォルトは US-ASCII (または -K で指定)✓
18/45
Rubyのエンコーディング - NSEG#30 Powered by Rabbit 1.0.9
スクリプトエンコーディング
US-ASCII で範囲外の "\xHH" 表記を含む場合は ASCII-8BIT
✓
"\uXXXX" 表記を含む場合は UTF-8
# coding: us-ascii"a".encoding #=> #<Encoding:US-ASCII>"\x41".encoding #=> #<Encoding:US-ASCII>"\xFF".encoding #=> #<Encoding:ASCII-8BIT>"\u3042".encoding #=> #<Encoding:UTF-8>
✓
19/45
Rubyのエンコーディング - NSEG#30 Powered by Rabbit 1.0.9
外部エンコーディング
ファイル内の文字列が何のエンコーディングかを指定する
✓
File.open 時に指定する
f = File.open("file.txt", "r:utf-8")f.gets # UTF-8文字列
ファイルの内容は UTF-8✓
読み込んだ文字列も UTF-8 エンコーディング✓
✓
20/45
Rubyのエンコーディング - NSEG#30 Powered by Rabbit 1.0.9
外部エンコーディング(書き込み)
f = File.open("file.txt", "w:utf-8")f.puts("ほげ")
文字列が UTF-8 に変換されて書き込まれる✓
21/45
Rubyのエンコーディング - NSEG#30 Powered by Rabbit 1.0.9
内部エンコーディング
ファイルから読み込んだ文字列のエンコーディングを変換する
✓
File.open 時に指定する
File.open("file.txt", "r:cp932:utf-8")
ファイルの内容は CP932✓
読み込んだ文字列は UTF-8 エンコーディング✓
書き込み時はあまり関係ない✓
✓
22/45
Rubyのエンコーディング - NSEG#30 Powered by Rabbit 1.0.9
もうちょっと詳しく
23/45
Rubyのエンコーディング - NSEG#30 Powered by Rabbit 1.0.9
読み込み時の変換
メソッドによって変換したりしなかったり✓
バイナリ読み込みメソッド(常に ASCII-8BIT)
read(n) / read_nonblock / readpartial / sysread
✓
✓
テキスト読み込みメソッド
foreach / readlines / each_line / lines / gets / getc / ungetc / read / readchar / readline / readlines
✓
✓
24/45
Rubyのエンコーディング - NSEG#30 Powered by Rabbit 1.0.9
外部エンコーディング未指定時
読み込み時は Encoding.default_external が使われる
Encoding.default_external #=> #<Encoding:UTF-8>
File.open("file.txt", "r:cp932").gets.encoding #=> #<Encoding:Windows-31J>
File.open("file.txt", "r").gets.encoding #=> #<Encoding:UTF-8>
25/45
Rubyのエンコーディング - NSEG#30 Powered by Rabbit 1.0.9
Encoding.default_external
-E オプション / ロケール
% ruby -Eutf-8 -e 'p Encoding.default_external'#<Encoding:UTF-8>% LC_ALL=C ruby -e 'p Encoding.default_external'#<Encoding:US-ASCII>% LC_ALL=ja_JP.UTF-8 ruby -e 'p Encoding.default_external'#<Encoding:UTF-8>
✓
かならず値がある✓
外部エンコーディングのデフォルトじゃない✓
26/45
Rubyのエンコーディング - NSEG#30 Powered by Rabbit 1.0.9
書き込み時の変換
メソッドには依らない✓
IO に外部エンコーディングが指定されていた場合は変換される
✓
外部エンコーディングが ASCII-8BIT の場合は変換されない
✓
外部エンコーディングが指定されていない場合は変換されない(基本的には)
✓
27/45
Rubyのエンコーディング - NSEG#30 Powered by Rabbit 1.0.9
正規表現のエンコー
ディング28/45
Rubyのエンコーディング - NSEG#30 Powered by Rabbit 1.0.9
正規表現リテラル
ASCII文字のみの場合は US-ASCII✓
非ASCII文字はスクリプトエンコーディング
# coding: utf-8/あ/.encoding #=> #<Encoding:UTF-8>/./.encoding #=> #<Encoding:US-ASCII>/./n.encoding #=> #<Encoding:US-ASCII>/./s.encoding #=> #<Encoding:Windows-31J>/./e.encoding #=> #<Encoding:EUC-JP>/./u.encoding #=> #<Encoding:UTF-8>
✓
29/45
Rubyのエンコーディング - NSEG#30 Powered by Rabbit 1.0.9
正規表現リテラル
US-ASCII で範囲外の "\xHH" 表記を含む場合は ASCII-8BIT
✓
"\uXXXX" 表記を含む場合は UTF-8
# coding: us-ascii/a/.encoding #=> #<Encoding:US-ASCII>/\x41/.encoding #=> #<Encoding:US-ASCII>/\xFF/.encoding #=> #<Encoding:ASCII-8BIT>/\u3042/.encoding #=> #<Encoding:UTF-8>
✓
30/45
Rubyのエンコーディング - NSEG#30 Powered by Rabbit 1.0.9
はまりどころ
31/45
Rubyのエンコーディング - NSEG#30 Powered by Rabbit 1.0.9
文字列比較
文字が等しくてもエンコーディングが異なれば異なる
u = "あ".encode("utf-8")s = "あ".encode("cp932")u == s #=> false
32/45
Rubyのエンコーディング - NSEG#30 Powered by Rabbit 1.0.9
文字列比較
バイト列が等しくてもエンコーディングが異なれば異なる
# coding: utf-8u = "あ"b = "あ".force_encoding("ascii-8bit")u == b #=> false
33/45
Rubyのエンコーディング - NSEG#30 Powered by Rabbit 1.0.9
文字列比較
エンコーディングが異なっていてもASCII互換のエンコーディングでASCII文字だけなら比較できる
# coding: utf-8u = "abc".encode("utf-8")s = "abc".encode("cp932")u == s #=> true
34/45
Rubyのエンコーディング - NSEG#30 Powered by Rabbit 1.0.9
正規表現
エンコーディングが異なっていたらエラー
# coding: utf-8"あ" =~ /./s# incompatible encoding regexp match (Windows-31J regexp# with UTF-8 string) (Encoding::CompatibilityError)
35/45
Rubyのエンコーディング - NSEG#30 Powered by Rabbit 1.0.9
正規表現
ASCII文字だけならエラーにならない
# coding: utf-8"ABC" =~ /./s
ASCII文字だけでテストしたりすると本番で落ちたり
36/45
Rubyのエンコーディング - NSEG#30 Powered by Rabbit 1.0.9
文字列結合
異なるエンコーディング同士の結合はエラー
u = "あ".encode("utf-8")s = "あ".encode("cp932")u + s# incompatible character encodings: UTF-8 and Windows-31J# (Encoding::CompatibilityError)
37/45
Rubyのエンコーディング - NSEG#30 Powered by Rabbit 1.0.9
文字列結合
ASCII文字だけならエラーにならない
u = "ABC".encode("utf-8")s = "DEF".encode("cp932")u + s #=> "ABCDEF" (UTF-8)
38/45
Rubyのエンコーディング - NSEG#30 Powered by Rabbit 1.0.9
リテラル
スクリプトエンコーディングに合わない文字があるとスクリプトのロード時にエラー
# coding: cp932"あ" # UTF-8の「あ」
# invalid multibyte char (Windows-31J)
39/45
Rubyのエンコーディング - NSEG#30 Powered by Rabbit 1.0.9
リテラル
でも "\xHH" 表記だとエラーにならない
# coding: cp932"\xE3\x81\x82" # UTF-8の「あ」
40/45
Rubyのエンコーディング - NSEG#30 Powered by Rabbit 1.0.9
不正な文字
正規表現との比較でエラー
# coding: cp932str = "\xE3\x81\x82" # ここではエラーにならないstr =~ /./ # invalid byte sequence in Windows-31J (ArgumentError)
41/45
Rubyのエンコーディング - NSEG#30 Powered by Rabbit 1.0.9
不正な文字
エンコーディングがあってたとしても不正な文字は発生しうる
# 不正な文字が入っているファイルをUTF-8指定で読んでしまったFile.open("utf-8.txt", "r:utf-8").gets # エラーにはならない
UTF-8 エンコーディングの文字列が得られるが、不正な文字が含まれているかもしれない
42/45
Rubyのエンコーディング - NSEG#30 Powered by Rabbit 1.0.9
変換
内部エンコーディングを指定すると不正な文字で変換エラー
# CP932だけど不正な文字が入ってるf = File.open("cp932.txt", "r:cp932:utf-8")f.gets # 不正な文字が含まれる行でエラー# `gets': "\xFC\xA1" from Windows-31J to UTF-8# (Encoding::UndefinedConversionError)
43/45
Rubyのエンコーディング - NSEG#30 Powered by Rabbit 1.0.9
変換
外部エンコーディングを指定してないと環境変数の影響うけるかも
✓
内部エンコーディング指定すると自動的に変換されるけど、読むだけでエラーになるかも
✓
44/45
Rubyのエンコーディング - NSEG#30 Powered by Rabbit 1.0.9
まとめ
文字単位の処理は便利✓
ハマる時はハマる✓
データのエンコーディングを統一するのが吉✓
45/45
top related