Ruby M17N RubyKaigi 08 RubyKaigi 08 Martin J. D ü rst.

58
Ruby Ruby M17N M17N RubyKaigi RubyKaigi 08 08 版版版版 版版版版 Martin J. D Martin J. D ü ü rst rst

Transcript of Ruby M17N RubyKaigi 08 RubyKaigi 08 Martin J. D ü rst.

Page 1: Ruby M17N RubyKaigi 08 RubyKaigi 08 Martin J. D ü rst.

Ruby Ruby M17NM17N― ― RubyKaigiRubyKaigi’’0808 版 版 ――

成瀬ゆい成瀬ゆいMartin J. DMartin J. Düürstrst

Page 2: Ruby M17N RubyKaigi 08 RubyKaigi 08 Martin J. D ü rst.

SummarySummary概論 概論 (intro) (intro) RubyRuby の場合 の場合 (Ruby(Ruby’’s s Case) Case)

変換 変換 (transcoding) (transcoding) by by MartinMartin

質疑応答 質疑応答 (questions)(questions)

Page 3: Ruby M17N RubyKaigi 08 RubyKaigi 08 Martin J. D ü rst.

Who is naruseWho is naruse

最年少コミッタ最年少コミッタ nkfnkf Softbank TechnologySoftbank Technology

– iPhoneiPhone とかとか [email protected]@ruby-lang.org

Page 4: Ruby M17N RubyKaigi 08 RubyKaigi 08 Martin J. D ü rst.

Ruby M17N Ruby M17N の特の特徴徴

CSI CSI 方式を採用方式を採用独自の変換モジュー独自の変換モジュールル

Page 5: Ruby M17N RubyKaigi 08 RubyKaigi 08 Martin J. D ü rst.

多言語化の手法多言語化の手法M17N methods:M17N methods:UCS Normalization UCS Normalization 方方式式

CSICSI 方式方式 (Code Set (Code Set Independent)Independent)

Page 6: Ruby M17N RubyKaigi 08 RubyKaigi 08 Martin J. D ü rst.

UCS Normalization UCS Normalization 方方式式

文字の内部表現を一つの文字の内部表現を一つの UCS UCS (Universal Character Set)(Universal Character Set) で統で統一一

文字列の入力時にデコード文字列の入力時にデコード出力時にエンコード出力時にエンコード他のほとんどの言語で採用他のほとんどの言語で採用

Page 7: Ruby M17N RubyKaigi 08 RubyKaigi 08 Martin J. D ü rst.

Perl's case (Unicode)Perl's case (Unicode)

Decode:Decode:

$str = decode("UTF-8", "\xE3\x81\$str = decode("UTF-8", "\xE3\x81\x82");x82");

$str → "$str → " ああ ""

Encode:Encode:

$bytes = encode("UTF-8", "$bytes = encode("UTF-8", " ああ ");");

$bytes → "\xE3\x81\x82"$bytes → "\xE3\x81\x82"

Page 8: Ruby M17N RubyKaigi 08 RubyKaigi 08 Martin J. D ü rst.

CSI CSI 方式方式 Code Set IndependentCode Set Independent 唯一特別なエンコーディングを持た唯一特別なエンコーディングを持た

ないない 不必要な変換は行わなくてよい不必要な変換は行わなくてよい Solaris, CitrusSolaris, Citrus 他に 他に __STDC_ISO_10646__ __STDC_ISO_10646__ でない でない

CC

Page 9: Ruby M17N RubyKaigi 08 RubyKaigi 08 Martin J. D ü rst.

RubyRuby の場合の場合String String がエンコーディングを持がエンコーディングを持

つつ中身はバイト列のまま中身はバイト列のまま"" あいうえおあいうえお ".encoding".encoding

-> <Encoding:UTF-8>-> <Encoding:UTF-8>

Page 10: Ruby M17N RubyKaigi 08 RubyKaigi 08 Martin J. D ü rst.

3 Encoding 3 Encoding GradesGrades

ASCII CompatibleASCII CompatibleASCII IncompatibleASCII IncompatibleDummyDummy

Page 11: Ruby M17N RubyKaigi 08 RubyKaigi 08 Martin J. D ü rst.

ASCII CompatibleASCII Compatiblefull supportfull supportscript encodingscript encodingfasterfasterUTF-8, Shift_JIS, EUC-JP, ...UTF-8, Shift_JIS, EUC-JP, ...

Page 12: Ruby M17N RubyKaigi 08 RubyKaigi 08 Martin J. D ü rst.

Major EncodingsMajor Encodings

US-ASCIIUS-ASCIIASCII-8BITASCII-8BITUTF-8UTF-8

Page 13: Ruby M17N RubyKaigi 08 RubyKaigi 08 Martin J. D ü rst.

Japanese Japanese EncodingsEncodings

Shift_JISShift_JISEUC-JPEUC-JP

Page 14: Ruby M17N RubyKaigi 08 RubyKaigi 08 Martin J. D ü rst.

Other Other EncodingsEncodings

Big5, EUC-KR, EUC-TW, GBK,Big5, EUC-KR, EUC-TW, GBK,

ISO-8859-X, KOI8-R, KOI8-U, ISO-8859-X, KOI8-R, KOI8-U, etcetc

Page 15: Ruby M17N RubyKaigi 08 RubyKaigi 08 Martin J. D ü rst.

Machine dependend Machine dependend EncodingsEncodings

Windows-31JWindows-31JCP51932CP51932eucJP-mseucJP-msWindows-125XWindows-125X

Page 16: Ruby M17N RubyKaigi 08 RubyKaigi 08 Martin J. D ü rst.

ASCII-8BITASCII-8BIT

ASCII Compatible 8BIT ASCII Compatible 8BIT StringString

BINARY?BINARY?

Page 17: Ruby M17N RubyKaigi 08 RubyKaigi 08 Martin J. D ü rst.

ASCII OnlyASCII Only7BIT String is special7BIT String is special"abcde".ascii_only? -> "abcde".ascii_only? -> truetrue

"abcde" + ""abcde" + " あいうえおあいうえお ""

Page 18: Ruby M17N RubyKaigi 08 RubyKaigi 08 Martin J. D ü rst.

ASCII IncompatibleASCII Incompatible

limited supportlimited supportCanCan’’t use as script t use as script encodingencoding

UTF-{16,32}{BE,LE}UTF-{16,32}{BE,LE}

Page 19: Ruby M17N RubyKaigi 08 RubyKaigi 08 Martin J. D ü rst.

UTF-16 & UTF-32UTF-16 & UTF-32UTF-16BE, UTF-16LEUTF-16BE, UTF-16LEUTF-32BE, UTF-32LEUTF-32BE, UTF-32LEしかし、しかし、 UTF-16 UTF-16 や や UTF-UTF-32 32 には非対応には非対応

Page 20: Ruby M17N RubyKaigi 08 RubyKaigi 08 Martin J. D ü rst.

Dummy encodingDummy encodingRuby Ruby は名前を知っているだは名前を知っているだ

けけ「文字」のサポートはしない「文字」のサポートはしないfor stateful encodingsfor stateful encodingsEncoding#dummy? -> trueEncoding#dummy? -> trueISO-2022-JP, UTF-7ISO-2022-JP, UTF-7

Page 21: Ruby M17N RubyKaigi 08 RubyKaigi 08 Martin J. D ü rst.

Encoding.listEncoding.listEncoding.listEncoding.list

→ → [encoding, ..][encoding, ..]Encoding.name_listEncoding.name_list

→ → [enc_name, ..][enc_name, ..]Encoding.aliasesEncoding.aliases

→ → {alias => enc_name, ..}{alias => enc_name, ..}

Page 22: Ruby M17N RubyKaigi 08 RubyKaigi 08 Martin J. D ü rst.

$KCODE is obsolete$KCODE is obsolete

$KCODE$KCODE は内部コード指定のため使われは内部コード指定のため使われたた

Ruby1.9Ruby1.9 ではシステム全体の内部コードではシステム全体の内部コードは、は、

決定不可能なため、廃止。決定不可能なため、廃止。 $KCODE$KCODE を参照しているスクリプトは注を参照しているスクリプトは注

意意

Page 23: Ruby M17N RubyKaigi 08 RubyKaigi 08 Martin J. D ü rst.

StringString

1.8: Byte String1.8: Byte String– Ruby ignores encodingRuby ignores encoding

1.9: Byte String with encoding1.9: Byte String with encoding– Ruby knows the encoding of Ruby knows the encoding of

stringstring

Page 24: Ruby M17N RubyKaigi 08 RubyKaigi 08 Martin J. D ü rst.

No Character No Character ObjectObject

but 1 Character Stringbut 1 Character String

?? ああ .class -> String.class -> String

Why?Why?

Page 25: Ruby M17N RubyKaigi 08 RubyKaigi 08 Martin J. D ü rst.

A character has A character has ......codepointcodepoint

encodingencodingbyte stringbyte string1 char string has them!1 char string has them!cf.cf. 大クラス主義大クラス主義

Page 26: Ruby M17N RubyKaigi 08 RubyKaigi 08 Martin J. D ü rst.

文字リテラル文字リテラル

1.8:1.8: ?a?a

→ → 97 (Fixnum)97 (Fixnum) ?\x61?\x61

→ → 97 (Fixnum)97 (Fixnum)

1.9:1.9: ?a?a

→ → "a" (US-ASCII)"a" (US-ASCII) ?\x61?\x61

→ → "a" (US-ASCII)"a" (US-ASCII) ?? ああ

→ → "" ああ " (UTF-8)" (UTF-8) ?\u{3042}?\u{3042}

→ → "" ああ " (UTF-8)" (UTF-8)

Page 27: Ruby M17N RubyKaigi 08 RubyKaigi 08 Martin J. D ü rst.

String#ord and Integer#chrString#ord and Integer#chr

"" ああ ".ord → 12354 # Unicode".ord → 12354 # Unicode 12354.chr12354.chr

→ → RangeError: 12354 out of char RangeError: 12354 out of char rangerange

12354.chr("UTF-8")12354.chr("UTF-8")

→ → "" ああ ""

Page 28: Ruby M17N RubyKaigi 08 RubyKaigi 08 Martin J. D ü rst.

文字列のエンコーディン文字列のエンコーディンググ

?a.encoding → <Encoding:US-ASCII>?a.encoding → <Encoding:US-ASCII> "a".encoding → <Encoding:US-ASCII>"a".encoding → <Encoding:US-ASCII> "\xFF".encoding → "\xFF".encoding → <Encoding:ASCII-<Encoding:ASCII-

8BIT>8BIT> "\u{3042}".encoding → "\u{3042}".encoding →

<Encoding:UTF-8><Encoding:UTF-8> "\u{3042 3044 3046}".encoding"\u{3042 3044 3046}".encoding

→ → <Encoding:UTF-8><Encoding:UTF-8>

Page 29: Ruby M17N RubyKaigi 08 RubyKaigi 08 Martin J. D ü rst.

String#[] → String#[] → 文字文字

1.8:1.8: String#[]String#[] → integer (1 byte)→ integer (1 byte) ““ あいうあいう””[0][0] → 0xE3 # UTF-8→ 0xE3 # UTF-8

1.9:1.9: String#[]String#[] → 1 → 1 文字 文字 stringstring ““ あいうあいう””[0][0] → "→ " ああ ""

Page 30: Ruby M17N RubyKaigi 08 RubyKaigi 08 Martin J. D ü rst.

String#lengthString#length

1.8:1.8: String#lengthString#length → byte length→ byte length ““ あいうあいう””.length.length → 9 (UTF-8)→ 9 (UTF-8) 1.9:1.9: String#lengthString#length → character length→ character length ““ あいうあいう””.length.length → 3→ 3 String#bytesizeString#bytesize → byte length→ byte length ““ あいうあいう””.bytesize.bytesize → 9 (UTF-8)→ 9 (UTF-8)

Page 31: Ruby M17N RubyKaigi 08 RubyKaigi 08 Martin J. D ü rst.

String is not EnumerableString is not Enumerable

String#each is removed.String#each is removed.

"hoge".each{|l|p l}"hoge".each{|l|p l}

→→ NoMethodErrorNoMethodError

Page 32: Ruby M17N RubyKaigi 08 RubyKaigi 08 Martin J. D ü rst.

String#each_*String#each_*String#each_byte String#each_byte (bytes)(bytes)

String#each_char String#each_char (chars)(chars)

String#each_line String#each_line (lines)(lines)

Page 33: Ruby M17N RubyKaigi 08 RubyKaigi 08 Martin J. D ü rst.

文字列の比較・結合文字列の比較・結合 同じエンコーディングの時に比較 結合可・同じエンコーディングの時に比較 結合可・

能能 バイト列として一致し、バイト列として一致し、

エンコーディングも等しい時に エンコーディングも等しい時に == == 成成立立(( 違うと 違うと ArgumentError)ArgumentError)

7bit7bit のみの文字列は特別のみの文字列は特別

Page 34: Ruby M17N RubyKaigi 08 RubyKaigi 08 Martin J. D ü rst.

正規表現マッチ正規表現マッチ

/(.)/ =~ "/(.)/ =~ " あいうあいう ""$1 → "$1 → " ああ ""

Page 35: Ruby M17N RubyKaigi 08 RubyKaigi 08 Martin J. D ü rst.

バイト列とのマッチバイト列とのマッチ

/\xE3\x81\x82/n =~ "/\xE3\x81\x82/n =~ " ああ ""→ → ArgumentError:ArgumentError: incompatible encoding regexp match incompatible encoding regexp match (ASCII-8BIT regexp with UTF-8 string)(ASCII-8BIT regexp with UTF-8 string)

両者とも 両者とも ASCII-8BIT ASCII-8BIT にして行うのが正解にして行うのが正解∵∵ これはバイト列処理であって、文字列処これはバイト列処理であって、文字列処理ではない理ではない

Page 36: Ruby M17N RubyKaigi 08 RubyKaigi 08 Martin J. D ü rst.

バイト列に対するマッバイト列に対するマッチチ

bytes = "Abytes = "Aああ ".force_encoding(".force_encoding(

"ASCII-8BIT")"ASCII-8BIT")/\xE3\x81\x82/ =~ bytes → /\xE3\x81\x82/ =~ bytes →

11/a/ =~ bytes → 0/a/ =~ bytes → 0

Page 37: Ruby M17N RubyKaigi 08 RubyKaigi 08 Martin J. D ü rst.

Script EncodingScript Encoding以下のエンコーディングを以下のエンコーディングを決定決定

文字リテラル文字リテラル文字列リテラル文字列リテラル正規表現リテラル正規表現リテラル

Page 38: Ruby M17N RubyKaigi 08 RubyKaigi 08 Martin J. D ü rst.

Magic Magic CommentComment

#!/bin/env ruby#!/bin/env ruby

# -*- coding: UTF-8 -*-# -*- coding: UTF-8 -*-

/coding[:=]\s*(?/coding[:=]\s*(?<encname><encname>

[\w.-]+)[^\w.-]/[\w.-]+)[^\w.-]/

Page 39: Ruby M17N RubyKaigi 08 RubyKaigi 08 Martin J. D ü rst.

-K option-K option

-K-K オプションは健在ですオプションは健在ですEncoding.external_encoding Encoding.external_encoding

に影響に影響script encoding script encoding にも影響すにも影響す

る。る。-E-E オプションは影響しない オプションは影響しない

(external encoding (external encoding にのみ影にのみ影響響 ))

Page 40: Ruby M17N RubyKaigi 08 RubyKaigi 08 Martin J. D ü rst.

script encodingscript encoding

通常のスクリプ通常のスクリプトト

1.1. magic magic commentcomment

2.2. -K-K

3.3. US-ASCIIUS-ASCII-E-E は影響しないは影響しない

-e-e およびおよび stdinstdin1.1. magic magic

commentcomment

2.2. -K or -K or ––EE

3.3. LocaleLocale

デフォルトはデフォルトはlocalelocale

Page 41: Ruby M17N RubyKaigi 08 RubyKaigi 08 Martin J. D ü rst.

String#inspect vs String#inspect vs String#dumpString#dump

String#inspectString#inspectぱっと見用ぱっと見用String#dump:String#dump:dumpdump 用用EscapeEscape 用には用には dumpdump を!を!

Page 42: Ruby M17N RubyKaigi 08 RubyKaigi 08 Martin J. D ü rst.

IO openIO open

open(path, "r:utf-8") open(path, "r:utf-8") {|f| puts {|f| puts f.gets }f.gets }

open(path, "r:utf-8:euc-jp") open(path, "r:utf-8:euc-jp") {.. }{.. }

open(path,open(path,"mode:external:inter"mode:external:internal")nal")

Page 43: Ruby M17N RubyKaigi 08 RubyKaigi 08 Martin J. D ü rst.

IO with encoding optionIO with encoding option

open(path, encoding: "utf-8")open(path, encoding: "utf-8") open(path,open(path, encoding: "utf- encoding: "utf-

8:euc-jp")8:euc-jp") open(path, encoding: open(path, encoding:

""external:internalexternal:internal")")

Page 44: Ruby M17N RubyKaigi 08 RubyKaigi 08 Martin J. D ü rst.

IO with encoding optionIO with encoding option

open(path,open(path,

external_encoding: "utf-8")external_encoding: "utf-8")open(path,open(path,

external_encoding: "utf-8external_encoding: "utf-8““,,

internal_encoding: "euc-jp")internal_encoding: "euc-jp")

Page 45: Ruby M17N RubyKaigi 08 RubyKaigi 08 Martin J. D ü rst.

Encoding.defult_externEncoding.defult_externalal

Default encoding for external Default encoding for external inputinput

-K or -E > locale-K or -E > locale

Page 46: Ruby M17N RubyKaigi 08 RubyKaigi 08 Martin J. D ü rst.

String as BytesString as BytesString#getbyte(index)String#getbyte(index)String#setbyte(index, String#setbyte(index, value)value)

String#bytesizeString#bytesize

Page 47: Ruby M17N RubyKaigi 08 RubyKaigi 08 Martin J. D ü rst.

transcodingtranscoding

MartinMartin さんよりさんより http://www.sw.it.aoyama.ac.jp/2008/

pub/RubyKaigiM17N.html

Page 48: Ruby M17N RubyKaigi 08 RubyKaigi 08 Martin J. D ü rst.

まとめまとめ Encoding Encoding を意識しようを意識しよう EncodingEncoding 独立なコードを書こう独立なコードを書こう String#encodeString#encode 便利便利

Magic comment Magic comment を書を書こうこう

Page 49: Ruby M17N RubyKaigi 08 RubyKaigi 08 Martin J. D ü rst.

今後の予定?今後の予定? Dir.open Dir.open 関連関連 その他 その他 encoding encoding を今扱えないメを今扱えないメ

ソッドソッド– Dir.glob, fnmatchDir.glob, fnmatch

String#encode (transcode) String#encode (transcode) のサのサポートポート

Unicode Unicode 版 版 Win32API Win32API の利用の利用 ??

Page 50: Ruby M17N RubyKaigi 08 RubyKaigi 08 Martin J. D ü rst.

RubyM17NRubyM17N の冒険の冒険はは

まだまだまだまだ始まったばかりだ 始まったばかりだ !!!!!!

Page 51: Ruby M17N RubyKaigi 08 RubyKaigi 08 Martin J. D ü rst.

質疑応答質疑応答

any questions?any questions?

Page 52: Ruby M17N RubyKaigi 08 RubyKaigi 08 Martin J. D ü rst.

戦略戦略

* UCS* UCS で行くかで行くか * * CSICSI で行くかで行くか

Page 53: Ruby M17N RubyKaigi 08 RubyKaigi 08 Martin J. D ü rst.

UCSUCS の場合の場合

* UCS* UCS を一つ決めるを一つ決める * * magic commentmagic comment を書くを書く * * UCSUCS 以外は変換以外は変換

Page 54: Ruby M17N RubyKaigi 08 RubyKaigi 08 Martin J. D ü rst.

CSICSI の場合の場合

* encoding* encoding に依存しないコードを書くに依存しないコードを書く * * magic commentmagic comment は不要は不要

Page 55: Ruby M17N RubyKaigi 08 RubyKaigi 08 Martin J. D ü rst.

FAQFAQ

Any questions?Any questions?

Page 56: Ruby M17N RubyKaigi 08 RubyKaigi 08 Martin J. D ü rst.

自動変換して結合自動変換して結合

* * 情報の欠落が発生するので困難情報の欠落が発生するので困難 * * US-ASCII US-ASCII で現在部分的に実現で現在部分的に実現

Page 57: Ruby M17N RubyKaigi 08 RubyKaigi 08 Martin J. D ü rst.

[0x3042,0x3044].pack("U")[0x3042,0x3044].pack("U")

* pack("U*") * pack("U*") の結果に の結果に encoding encoding をつをつけてほしいけてほしい

* * pack("U*") pack("U*") では では UTF-8 UTF-8 であると断定であると断定できるが、できるが、

* * pack("UC") pack("UC") では不定なので難しい。では不定なので難しい。

Page 58: Ruby M17N RubyKaigi 08 RubyKaigi 08 Martin J. D ü rst.

ライブラリのエンコーディングライブラリのエンコーディング

require require でエンコーディングの指定は不でエンコーディングの指定は不可能可能

US-ASCIIUS-ASCII で書こうで書こう