これは「Ruby脳にはCrystalつらい Advent Calendar 2015」の19日目の記事です。
昨日の記事で Crystal の文字列は UTF-8 だと書きましたが、実行時に外部から UTF-8 以外の文字列を与えるとどうなるのでしょうか。
p File.open("/dev/urandom").gets
% crystal hoge.cr Invalid byte sequence in UTF-8 string (InvalidByteSequenceError) [4350519] *CallStack::unwind:Array(Pointer(Void)) +87 [4350410] *CallStack#initialize<CallStack>:Array(Pointer(Void)) +10 [4350362] *CallStack::new:CallStack +42 [4438767] *Exception +31 [4438701] *InvalidByteSequenceError#initialize<InvalidByteSequenceError, String>:CallStack +29 [4438641] *InvalidByteSequenceError::new<String>:InvalidByteSequenceError +97 [4438533] *InvalidByteSequenceError::new:InvalidByteSequenceError +21 [4455450] *Char::Reader#invalid_byte_sequence<Char::Reader>:NoReturn +10 [4454605] *Char::Reader#decode_current_char<Char::Reader>:Char +157 [4454434] *Char::Reader#initialize<Char::Reader, String>:Char +34 [4454338] *Char::Reader::new<String>:Char::Reader +98 [4348954] *String#inspect<String, IO::FileDescriptor>:IO::FileDescriptor +90 [4342179] *p<String?>:String? +115 [4333778] ??? [4340752] main +32 [139929057270336] __libc_start_main +240 [4331145] _start +41 [0] ???
実行時エラーになりました。
ただし、このエラーは読み込んだ文字列を文字単位で評価しようとした時に発生します。
line = File.open("/dev/urandom").gets if line.is_a? String # gets は nil を返すことがあるためこの if が必要 p line.size line.each_char do |c| p c end end
% crystal hoge.cr 96 '܄' '\u{5}' Invalid byte sequence in UTF-8 string (InvalidByteSequenceError) [4349767] *CallStack::unwind:Array(Pointer(Void)) +87 [4349658] *CallStack#initialize<CallStack>:Array(Pointer(Void)) +10 [4349610] *CallStack::new:CallStack +42 [4438095] *Exception +31 [4438029] *InvalidByteSequenceError#initialize<InvalidByteSequenceError, String>:CallStack +29 [4437969] *InvalidByteSequenceError::new<String>:InvalidByteSequenceError +97 [4437861] *InvalidByteSequenceError::new:InvalidByteSequenceError +21 [4454746] *Char::Reader#invalid_byte_sequence<Char::Reader>:NoReturn +10 [4453901] *Char::Reader#decode_current_char<Char::Reader>:Char +157 [4334218] ??? [4341200] main +32 [140711960898112] __libc_start_main +240 [4331017] _start +41 [0] ???
File#gets
でもなく、String#size
でもなく、String#each_char
で UTF-8 として不正な文字を取り出した時にエラーになっています。
Ruby と異なり、エンコーディングを変換したり UTF-8 として正しいバイト列かどうかを判定する方法もありません。つらい。