レシピブック雑談
内部エンコーディングと外部エンコーディング
- 内部エンコーディング
- 外部エンコーディング
- ソースコードのエンコーディング
と、3つエンコーディングがあってわかりにくい。
3つばらばらなことはあまりないんだけど、あえてバラバラにするとこんな感じ:
# coding:euc-jp
Encoding::default_internal="Windows-31J"
Encoding::default_external="GB18030"
# ソースコード内にある文字列は、そのソースコードのエンコーディング。
p "あ".encoding.name #=> "EUC-JP"
# デフォルトに従い、GB18030 だと思い込んで読み、"Windows-31J" に変換してから文字列にする。
p File.open( "somefile.GB18030" ).read.encoding.name #=> "Windows-31J"
# 引数に従い、euc-jp だと思い込んで読み、デフォルトにしたがって "Windows-31J" に変換してから文字列にする。
p File.open( "somefile.euc-jp", "r:euc-jp" ).read.encoding.name #=>"Windows-31J"
# 引数に従い、euc-jp だと思い込んで読み、"UTF-16LE" に変換してから文字列にする。
p File.open( "somefile.euc-jp", "r:euc-jp:utf-16le" ).read.encoding.name #=> "UTF-16LE"
普通は
- ソースコードのエンコーディングは utf-8。
- 内部エンコーディングも utf-8。
- 外部エンコーディングもできるだけ utf-8 にしたいけど、エクセルが吐いた CSV を読むから "Windows-31J" とか、そういうことはある。
という対応にすると思う。
リテラル
ruby 2.2.0 には、レシピブックにないリテラルがある。
1i #=> (0+1i)
1r #=> (1/1)
1ri #=> (0+(1/1)*i)
%i( foo bar baz ) #=> [:foo, :bar, :baz]
二種類の比較スペースシップと不等号
<=>
があれば <
, >
は論理的には存在可能なのでありそうな気もするんだけど、
[1]<=>[2] #=> -1
[1]<[2] #=> undefined method `<' for [1]:Array
と、スペースシップがあっても不等号があるとは限らない。
文字の出現頻度と itself
レシピブックのレシピ34で、文字列に含まれる文字の出現回数を数えてるけど、ruby1.9 を使ってよければこう書くよ、という話。
def char_count_list(str)
str.chars.group_by{|c|c}.map{|k,v|[k,v.size ]}.sort_by{|x| -x.last}
end
そうそう。2.2 だと itself
が使えるから
def char_count_list(str)
str.chars.group_by(&:itself).map{|k,v|[k,v.size ]}.sort_by{|x| -x.last}
end
と書ける。
当日は思いつかなかったけど、これが itself
の期待されている使い方だと思う。
hex, to_i, to_f
数を表す文字列を数値に変換するときにひどい目に合うことがある。
有名なのは JavaScript の parseInt だよね。
と思ったら、0 で始まっても8進数にならなくなったらしい。
https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Global_Objects/parseInt
によると、Firefox は 21 ( 2013 年 5 月 )から。
実行結果は以下のとおり(Node.js v0.10.35):
parseInt("012") // => 12
parseInt("0x12") // => 18
parseInt("12") // => 12
parseInt("12e8") // => 12
parseInt("12.99") // => 12
parseInt(".99") // => NaN
parseInt("0.99") // => 0
parseInt("+2") // => 2
parseInt("-2") // => -2
parseInt(" -2 ") // => -2
parseInt(" +2 ") // => 2
parseInt("-+2") // => NaN
parseInt("++2") // => NaN
parseInt(" 2 ") // => 2
parseInt(" + 2 ") // => NaN
parseInt(" - 2 ") // => NaN
parseInt("-0x12") // => -18
parseInt("0y12") // => 0
parseInt("0xx") // => NaN
parseInt("0yy") // => 0
"0xx"
が NaN になるのが意外だった。
ruby の to_i
もちょっとおもしろい動きをする。
下表の通り。
receiver | .to_i |
.to_i(16) |
.to_i(8) |
.to_i(2) |
.hex |
.to_f |
---|---|---|---|---|---|---|
0d12 |
12 |
3346 |
0 |
0 |
3346 |
0.0 |
0x12 |
0 |
18 |
0 |
0 |
18 |
0.0 |
0o12 |
0 |
0 |
10 |
0 |
0 |
0.0 |
012 |
12 |
18 |
10 |
1 |
18 |
12.0 |
0b101 |
0 |
45313 |
0 |
5 |
45313 |
0.0 |
1e23 |
1 |
7715 |
1 |
1 |
7715 |
1.0e+23 |
0xx |
0 |
0 |
0 |
0 |
0 |
0.0 |
0yy |
0 |
0 |
0 |
0 |
0 |
0.0 |
.1 |
0 |
0 |
0 |
0 |
0 |
0.1 |
0x1.2 |
0 |
1 |
0 |
0 |
1 |
0.0 |
+1 |
1 |
1 |
1 |
1 |
1 |
1.0 |
+ 1 |
0 |
0 |
0 |
0 |
0 |
0.0 |
ruby には 0d
という 10 進数を表す記号があって、16進数との混乱がある。
実用上困るシーンは思いつかないけどね。
JavaScript の parseInt
と異なり、to_i は、0x12
の先頭を 16進数の prefix とはみなさない。
0xx
のようなおかしい入力を、JavaScript の parseInt
は NaN
にするけど、ruby は 0
にする。私としては ruby の方が自然な感じがする。
その他の話題
Yosemite + QuickTime Player で、iPhone の画面を Mac 上に表示できる。
ああそんな機能あったっけ、と思った。