Object#inspect は Encoding.default_external の影響を受ける


Ruby の inspect メソッドは Encoding.default_external の影響を受けるようだ。

まず,String オブジェクトがどんなバイト列になっているのかを調べるメソッドを定義しておく。

class String
  def byte_sequence
    bytes.map{|b| "%0X" % b}.join(" ")
  end
end

そのうえで,default_external を変えて文字列「」を inspect してみる。

Encoding.default_external = "UTF-8"
puts "あ".inspect.byte_sequence
#=> 22 E3 81 82 22

Encoding.default_external = "CP932"
puts "あ".inspect.byte_sequence
#=> 22 5C 75 33 30 34 32 22

それぞれの先頭と末尾にある 0x22 はダブルクオート " だ。

UTF-8 版で,ダブルクオートに囲まれた E3 81 82 は UTF-8 での のバイト列だ。

一方,CP932(いわゆる Windows 版 Shift JIS;「Windows 31J」ともいう)のほうは,\u3042 の形になっている。

そういえば,確かに

p "あ"

とやったとき,UTF-8 だと「"あ"」と表示されるが,CP932 だと「"\u3042"」と表示されたりするよな。

inspectp メソッドのためにある,と考えればこの仕様は理解できなくもない。

でも,こんな大事なことがリファレンスマニュアル

http://docs.ruby-lang.org/ja/2.3.0/method/Object/i/inspect.html
http://docs.ruby-lang.org/ja/2.3.0/method/String/i/inspect.html
http://docs.ruby-lang.org/ja/2.0.0/method/Regexp/i/inspect.html

のどこにも書いてない。

で,だ。inspect をデバッグなんか以外の目的で使いたいこともある。

今回のことに気づいたのも,ユーザーが入力した正規表現を HTML 形式のレポートの中に表示しようとして,Regexp#to_s だとイマイチなので Regexp#inspect にしたわけなのだが,日本語が混じってたときに \u3042 みたいになってて「あれ?」と思ったんだ。