ラベル ruby の投稿を表示しています。 すべての投稿を表示
ラベル ruby の投稿を表示しています。 すべての投稿を表示

2022年7月2日土曜日

続・Rubyの文字コード変換

そのうち作り直そうと思ってたものを、ようやく作り直した。

String#encodeを使って作り直したバージョンはこれ。使い方は変えていないので、以前と同じように使えるはず。パスが通ったところに置いて

% j2j -tu foo.txt bar.txt
と実行すれば、foo.txtとbar.txtをUTF-8に変換する。複数ファイルを入力する場合、入力ファイルの文字コードはバラバラでもOK。フィルタではなく指定ファイルを直接変更するので注意。

実行スクリプトの名前のサフィックスで、-tオプションのデフォルト値を指定する機能は残してある。例えばj2j.sjisという名前のシンボリックリンクを作っておけば

% j2j.sjis baz.txt
でbaz.txtをShift_JISに変換できる。

2022年6月26日日曜日

Rubyの文字コード変換

大昔に作った文字コード変換スクリプトを、久々に使おうとしたら動かなくなっていた。

とりあえずKconv::AUTOの値がnilになってしまい、想定外のraiseに引っ掛かるようになってしまったのと、String#kconvの挙動が怪しくなったような。もう深追いせず、String#encodeを使うよう作り直そうかな。

2021年5月3日月曜日

irbの色をカスタマイズする

macOS 11.3に上げたときだろうか? Rubyのバージョンが上がったのか、irbに色が付くようになった。

それだけ聞いたら悪くなさそうなんだけど、問題はその色の設定。ターミナルと言えば黒バックに白文字と刷り込まれているオッサンにとって、文字を青くされると非常に読みづらいんだわ、これが。

で、とりあえず色付けを無効化するには、~/.irbrcで以下のように設定すればOK。

IRB.conf[:USE_COLORIZE] = false

とは言え、せっかくなら色をカスタマイズして使いたいと思うのがプログラマというもの。ググっても設定が見つからなかったのでgems/irb-1.3.5/以下を覗いてみたところ、color.rbの中のTOKEN_SEQ_EXPRSで色を決めているらしい。そして、これを外から弄ることは想定されていない模様。そこで、~/.irbrcで以下のように無理矢理設定して、青を水色に変更した。

module IRB
  module Color
    TOKEN_SEQ_EXPRS[:on_CHAR] =      [[CYAN, BOLD], ALL]
    TOKEN_SEQ_EXPRS[:on_comment] =   [[CYAN, BOLD], ALL]
    TOKEN_SEQ_EXPRS[:on_const] =     [[CYAN, BOLD, UNDERLINE], ALL]
    TOKEN_SEQ_EXPRS[:on_ident] =     [[CYAN, BOLD], Ripper::EXPR_ENDFN]
    TOKEN_SEQ_EXPRS[:on_imaginary] = [[CYAN, BOLD], ALL]
    TOKEN_SEQ_EXPRS[:on_int] =       [[CYAN, BOLD], ALL]
    TOKEN_SEQ_EXPRS[:on_rational] =  [[CYAN, BOLD], ALL]
  end
end

ただ、問題はまだある。ざっと眺めてみただけでもcolor.rb, color_printer.rb, workspace.rbあたりで、BLUEとかGREENとか思いっきりハードコーディングされているのだ。こうなるともう、~/libとかにコピーしたものを自分好みの色にして、オリジナルより先にロードされるようにするしかないかなぁ。

酷い荒技として、~/.irbrcで以下のようなことをすれば、青を水色に置き換えられる。定数を書き換えるから怒られるし、前述のTOKEN_SEQ_EXPRSには効果がない(TOKEN_SEQ_EXPRSを定義する時点ではまだBLUEの定義が置き換わっていないので)。

IRB::Color::BLUE = IRB::Color::CYAN

まあ、正式な設定項目ができるまでの繋ぎかな。

2020年6月17日水曜日

Rubyのrequire_relative

Rubyのrequire_relativeは、どこからの相対パスなのか。

例えば、以下のようにスクリプトを配置している場合。

main.rb
sub0.rb
sub1/foo.rb
sub2/bar.rb
main.rbからsub0.rb, sub1/foo.rbをロードするには以下。まあ、これは直感的。
require_relative 'sub0'
require_relative 'sub1/foo'

では、main.rbからロードしているsub1/foo.rbからsub2/bar.rbをロードするにはどうするか。答えは以下。

require_relative '../sub2/bar'
大元のmain.rbがあるディレクトリからの相対パスではなく、直接require_relativeしているfoo.rbがあるsub1/からの相対パスとなる。直接起動したスクリプトがあるディレクトリを基点にするわけではない。ちょっと考えてみれば、ロード元スクリプトによって基点が変わるようでは、サブスクリプト間でロードしづらくてたまらないから、まあ正解な仕様だろう。

2015年10月28日水曜日

古いRubyでLazyを使う

RubyでLazyを使いたくても古いバージョンしか入っていない場合の対処。

module Enumerable
  unless defined? lazy
    def lazy
      each
    end
    alias :force :to_a
  end
end

…そう。2.x系向けに書いたEnumerable::lazyを使うコードを、とりあえず動くようにするだけのごまかしだ。本当に遅延評価するわけではないので、無限リストなんて使ったら無限ループに陥る。eachはEnumerableのメソッドではないので、lazyをeachのエイリアスにはできない。

2015年8月20日木曜日

Rubyの ... 演算子

10年以上Rubyを使っていて、今更ながら ... 演算子を知った。

.. 演算子と同様にRangeオブジェクトを返すのだが、...で生成したRangeオブジェクトは範囲の末尾を含まない。Numeric a, bに対するa..bはa以上b以下を意味するのに対し、a...bはa以上b未満を意味する。手っ取り早く実例。

irb> (0..3).last
=> 3
irb> (0...3).last
=> 3
irb> (0..3).exclude_end?
=> false
irb> (0...3).exclude_end?
=> true
irb> (0..3).include?(3)
=> true
irb> (0...3).include?(3)
=> false
irb> (0..3).each {|i| p i}
0
1
2
3
=> 0..3
irb> (0...3).each {|i| p i}
0
1
2
=> 0...3
irb> (0..3) == (0...3)
=> false
irb> (0..2) == (0...3)
=> false

単なるループのためにRangeオブジェクトを作るケースで、末尾を含みたくないがためにa..(b-1)のようにしていたところを、a...bと書けるわけだ。

2015年8月13日木曜日

Homebrewのupdateでエラー

brew updateを実行したら、何やらエラーが出た。

% brew update
Error: uninitialized constant Formulary::HOMEBREW_CORE_FORMULA_REGEX
Please report this bug:
    https://git.io/brew-troubleshooting
/usr/local/Library/Homebrew/formulary.rb:227:in `loader_for'
/usr/local/Library/Homebrew/formulary.rb:176:in `factory'
/usr/local/Library/Homebrew/cmd/update.rb:205:in `block in report'
/usr/local/Library/Homebrew/cmd/update.rb:190:in `each_line'
/usr/local/Library/Homebrew/cmd/update.rb:190:in `report'
/usr/local/Library/Homebrew/cmd/update.rb:24:in `update'
/usr/local/Library/brew.rb:127:in `<main>'
zsh: exit 1     brew update

で、エラーメッセージでググってみたところ、もう1度brew updateを実行すれば通るとのこと。書いてあった通りbrew updateをやり直したらすんなり動作。意外な盲点だった。

2015年7月3日金曜日

CygwinでRubyを使う

64ビットCygwin環境でRubyを使えるようにする話。

CygwinにはRubyのパッケージがあるんだから、setup-x86_64.exeから道なりにインストールするだけだろう。そんなふうに考えていた時期が俺にもありました。

特にエラーもなくインストールできたと思って油断していたら、いざ使おうとしたときにrubygemsが見つからんと怒られて何もできない。Macから持ってきたドットファイルが環境変数RUBYLIBをおかしくしているのかと思ったものの、見当違い。これは何事? > 本当にrubygemsが入っていないだけでした。

失敗の遠因は、パッケージリストを上から眺めてInterpretersカテゴリの中から選んだrubyのパッケージを入れたこと。これでRubyのインストールが済んだものだとばかり思っていたのだけれど、パッケージリストのずっと下の方を見るとRubyカテゴリがあり、その中にrubygemsパッケージがあるのを発見。こいつをインストールしてようやくRubyを使えるようになった。パッケージの依存性がきちんと設定されていなかったのかな。

2014年9月27日土曜日

Rubyistが歩んでみる蛇の道はPython その7

Dive into Python 3に戻って、chapter 7と8からイテレータの話。

オブジェクトobjをlistやtupleのようにforでぶん回せる(iterableである)ようにするには、

  1. objが__iter__()メソッドを持っている
  2. obj.__iter__()が返すオブジェクトが__next__()メソッドを持っている
ようにすれば良い。大方の想像通り、iter(xx)するとxx.__iter__()が、next(yy)するとyy.__next__()が実行される。__next__()は、呼ばれる度に列挙される値を1つずつ返すようにする。また、列挙し終えたならStopIteration例外を投げる。端落ちしてもNoneが返されるので、列挙の終了とはみなされない。

では、generatorはどうしてiterableだったのか。別に特別扱いされていたわけでも何でもなく、generatorも上の条件を満たしていたのだ。

>>> def gen():
...   yield 0
...
>>> g = gen()
>>> g.__iter__
<method-wrapper '__iter__' of generator object at 0x10a88cf78>
>>> g == g.__iter__()
True
>>> g.__next__
<method-wrapper '__next__' of generator object at 0x10a88cf78>
>>> g.__next__()
0
>>> g.__next__()
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
StopIteration
generatorは実は、自分自身を返す__iter__()と、yieldした値を返す__next__()を持っていたのだ。なおgeneratorは、StopIterationを明示的にを投げなくてもreturnするときに投げてくれるようだ。普通の関数と違って、yieldとreturnを区別できるからだろうね。

ちなみに、普通のlistやtupleも例外ではなく、__next__()を持っているオブジェクトを返す__iter__()を持っている。

この緩い条件を満たしたiterableなオブジェクトから、別のiterableなオブジェクトを生成するitertoolsというライブラリが、Pythonには標準で付いている。chapter 8ではitertoolsの中からいくつかの関数を使って見せているけど、詳しくはhelp()で調べてみれば良いだろう(きちんとdocstringが用意されているって、地味に凄いことだよなぁ)。…と、これだけで片付けるのはあんまりなので、iteratorのありがたみを3行で表す(パッと見2行だけど、printの次の空行を含めて3行)。

for p in itertools.permutations(range(10000)):
  print(p)
順列を列挙するコードを自前で書かずに済むのはありがたいけど、それ以前にこのコードが動くこと自体がありがたい(実行に何年かかるか知らないが)。ちょっと考えれば分かるように、10000要素の整数リストを10000!個持つリストを作ってからループを回そうなんて思ったら、どう考えてもメモリが足りない。それでもこのコードが延々と順列を表示し続けてくれるのは、いきなり10000!通り全てを生成しようなんて馬鹿げたことをせず、next()の度に1つずつ列挙してくれているからだろう。ここらへんのケアをおまかせできるのは美味しい。

2014年9月25日木曜日

Rubyistが歩んでみる蛇の道はPython その6

Dive into Python 3のchapter 7を読んでみたのだが、Classes & Iteratorsなんて章の名前を付けている割に、そんなにクラスについて詳しく書いていない。具体的な継承の話なんか、まるで無いし。そこでググってみたところ、こちらの公式チュートリアルが良さそうなので、ざっと読んでみた。

多くの人が真っ先に面食らうのは、Rubyを含む多くのオブジェクト指向な言語ではimplicitに渡されるのが当たり前のselfやらthisやらが、Pythonのメソッド定義ではexplicitに第1引数として、インスタンス自身が渡される点だろう。この第1引数はselfという名前を使うことを推奨されているようだけれど、selfは単なる仮引数の名前であって予約語でも何でも無い。

そしてメソッド定義の中でさえ、インスタンス変数にはselfを介さないとアクセスできない。言い換えると、インスタンス変数はスコープに入らないのだ。Rubyだと

def method
  @member1 = 100
  print(@member2)
end
のようにアクセスできるところが、Pythonだと
def method(self):
  self.member1 = 100
  print(self.member2)
のようにせねばならない。

地味に嫌らしいと思うのが、Pythonではクラスのインスタンスを介してクラス変数にアクセスできる点。Pythonだと

class Foo:
  x = 100

foo = Foo()
print(foo.x)
こんなことが出来てしまう。Rubyでクラス定数を参照しようと思ったら
class Foo
  X = 100
end
print(Foo::X)
print(Foo.new.X) # error
のように、インスタンスではなくクラス名の修飾が必要。

他にも、public, protected, privateと言ったアクセス制限の機能がPythonにはない。_memberみたいに'_'を付けたメンバはprivate扱いしてね、みたいなコーディングルールで凌いでいるようだ。まあLLならそれくらいの緩さでも許されるだろう。

問題は継承。ずばり、Pythonは多重継承が出来る。これだけでもう、Rubyで言うところのmix-inだの、Javaで言うところのinterfaceだの、そんな細かい話は吹っ飛んでしまう。属性の検索が基本的に深さ優先探索で行われるというのも要注意だろう。A, Bの順に多重継承した場合、BよりAの曾祖父の方が先に探索されるのだ。実装を考えればそりゃそうなんだろうけど、普段から多重継承が制限された世界で過ごしていると違和感を禁じ得ない。

2014年9月23日火曜日

Rubyistが歩んでみる蛇の道はPython その5

Dive into Python 3のchapter 6をざっと読んでみた。

Pythonの関数はオブジェクトである。これはRubyの関数(メソッド)と非常に大きく異なる点だ。Pythonだと

>>> def foo():
..  print('foo')
..
>>> f = foo
>>> f()
foo
のように変数に直接関数を代入したり、代入した変数経由で元の関数を呼び出したりできる。…と言うか
>>> foo = 1
>>> foo()
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: 'int' object is not callable
>>> foo = f
>>> foo()
foo
こんなことができてしまうということは、fooは定数ですらないようだ。Pythonのdef文は、JavaScriptのfunctionと同じように関数オブジェクトを作って、それを何の変哲も無い普通の変数に代入しているだけみたい。

とにもかくにも、関数がオブジェクトであるということは、100やら'abc'やらと同じように普通に受け渡しが出来る。ここは正直Rubyの弱いところで、基本的に最大1つのブロックをメソッドに渡すことしかできない。一応:funcのようなシンボルでメソッド名を渡したり、lambda等でProcオブジェクトを作って渡したり、呼び出し先でevalしてもらうコードを文字列で渡したりすることはできるのだけれど、自然に関数を扱えるとは言い難い。まあ、Rubyではメソッドが特別扱いされているが故に

print 'ruby'
のように()を付けなくてもメソッド呼び出し出来るのは、ちゃちゃっと使い捨てコードを書くときに楽は楽なんだけど。

もう1点。RubyのProcにはないけどPythonの関数オブジェクトにはある機能に、中断/再開がある。

>>> def gen():
...   v = 0
...   while v <= 50:
...     yield v
...     v += 10
...
>>> g = gen()
>>> type(g)
<class 'generator'>
このように、内部でyield文を使った関数はgeneratorクラスのオブジェクトを返す。そして
>>> next(g)
0
>>> next(g)
10
>>> next(g)
20
>>> next(g)
30
>>> next(g)
40
>>> next(g)
50
>>> next(g)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
StopIteration
このようにnext文でgeneratorを呼び出す度に、関数オブジェクトがyieldした値が呼び出し元に返され、また関数オブジェクトの方はyieldしたところで中断する。ノンプリエンプティブなスレッドと言えなくもない。このgeneratorの嬉しいのは、リスト等と同じように
>>> for i in gen():
...   print(i)
...
0
10
20
30
40
50
こんな感じでイテレータとして使えるところ。イテレータの話は次の章で深追いするのかな?

2014年9月11日木曜日

Rubyistが歩んでみる蛇の道はPython その4

Dive into Python 3のchapter 5をさらりと読んでみた。

Rubyを含む他のLLと同様、Pythonでも正規表現は使える。が、意外なことに、reモジュールを明示的にimportしないと使えない。下の例はimport reを端折ると動かない。

>>> import re
>>> str = 'abcdefg'
>>> re.sub(r'c.e', 'XYZ', str)
'abXYZfg'
>>> m = re.search(r'.{4}$', str)
>>> m.group(0)
'defg'
同じことをRubyでやろうとするとこんな感じ。
irb> str = 'abcdefg'
irb> str.sub(/c.e/, 'XYZ')
=> "abXYZfg"
irb> m = /.{4}$/.match(str)
irb> m[0]
=> "defg"

ちなみにPythonのr'...'は、正規表現リテラルではなく単なる文字列リテラル。regular expressionではなくraw stringのr。rを付けるとRubyで言うところの'...'文字列のように、\等が特別扱いされなくなる。

さて、実質定数な正規表現でも、内部的には使う度に文字列から正規表現に変換しなければならないかと言うと、さすがにそんなことはなく、re.compile()を使えば正規表現オブジェクトを作成できる。また、その正規表現オブジェクトは、subだのsearchだの、reモジュールと同名の関数を持っている。もちろん、引数に正規表現文字列は取らないけど。

正規表現のオプションは、正規表現文字列を受け取るreモジュールの関数に引数flagsとして渡してやる。このflagsはデフォルト値0が設定されているので省略可能。Rubyで言うところの

r = /ab c/ix
が、Pythonでは
r = re.compile(r'ab c', re.I | re.X)
となる。ちとクドいね。あと、Rubyの正規表現にフリーフォーマットモード(x)があることを今更知った。

2014年9月9日火曜日

Rubyistが歩んでみる蛇の道はPython その3

Dive into Python 3のchapter 4をざっくり読んでみた。

Pythonは2から3で、文字列の扱いが大きく変わったそうな。具体的には、Unicodeで表現できる文字の並びをstringと、符号無し8ビットの値の並びをbytesを、明確に区別するようになった。

文字列の内部表現に関しては特に規定がなくて、UTF-8にするもUTF-32にするも実装の勝手なのかな。何であれ、Unicodeじゃない文字列を入力して文字列としてPythonで処理したければ、必ず文字コードの変換が入るわけだ。Rubyとの比較はるびまのM17Nの記事が良くまとまっているが、Rubyの場合は内部表現は統一していない。文字コードの変換とそれに関する問題から縁遠いのが長所だが、自分が処理系を実装するなら、面倒だからUTF-8あたりに統一するだろうなぁ。RubyはUnicodeと心中するつもりは無い、みたいなことをどこかで読んだような…。

話をPythonに戻すと、stringやbytesはimmutable。すなわち、stringやbytesのインスタンスは、何かを付け足したり削ったり、部分的に置き換えたりできない。

>>> s = 'abc'
>>> t = s
>>> s += 'def'
>>> s
'abcdef'
>>> t
'abc'
このように'abc'というインスタンスを'abcdef'に変更するわけではなく、あくまで'abcdef'というインスタンスを新たに生成するのだ。ただ、bytesに関してはmutableなbytearrayも存在するので、巨大なバイト列を扱うときなど、適宜bytearrayと使い分ければ良いのだろう。

formatは微妙。どうしてデファクトスタンダードであるCのprintfの書式を踏襲しなかったのか? 雰囲気はシェルスクリプトのpositional変数に似てるけど$記号は使わない。dictのキーとして文字列を指定するときに''で括らない等、文法的にも何となく気持ち悪い。

ソースの文字コードにUTF-8を推奨しているのはいいね。Shift_JISとCRLF改行のファイルを撒き散らすメモ帳は死ね。氏ねじゃなくて死ね。

2014年9月4日木曜日

Rubyistが歩んでみる蛇の道はPython その2

Dive into Python 3のchapter 3をさっくり読んでみた。

まずosモジュール。プラットフォーム依存を極力抑えるために用意されたAPIを詰め込んだモジュールだそうな。そこらへんRubyはUnix寄りな気がするけど、Pythonは中立を目指してるってことか。まあ、chapter 3で紹介されているAPIだけでは、理想を実現しているのかどうか判断しかねるけど。

Rubyと比較すると、DirやFileクラスの特異メソッドに分散している機能が、Pythonではosモジュールに集約されている印象。それでもglobはosに含まれないようだけど。

comprehension記法は、Rubyで言うところのmap(とif clauseをつければselect)の略記法だけど、dictにも使えるところがRubyにはない点。Pythonと比較してみて、今更RubyのHash#mapがHashを返さないことに気が付いた。あと、mapとselectの略記法とは言ったけれど、selectしてからmapするよりは中間オブジェクトが作られなさそう。実装は見てないけど。

2014年9月2日火曜日

Rubyistが歩んでみる蛇の道はPython その1

とりあえずDive into Python 3を、chapter 2までざっくり読んでみた。

まず、Rubyで言うところのirbに相当する機能が、Pythonには標準で備わっている。

% python3
Python 3.4.1 (default, Aug 24 2014, 21:32:40)
[GCC 4.2.1 Compatible Apple LLVM 5.1 (clang-503.0.40)] on darwin
Type "help", "copyright", "credits" or "license" for more information.
>>> 1+1
2
>>>
こんな感じで、引数無しで起動すればインタラクティブなモードになる。

Rubyistが注意しないと間違えそうなのは、if文の条件のようなbool型が要求されるところ。Rubyならfalseとnil以外はtrueと同じ扱いなのだが、PythonはFalseとNoneだけでなく、整数の0や浮動小数点数の0.0も偽扱い。0に関してはむしろRubyの方が特殊なのだが、Pythonでは更に要素数がゼロのlist, tuple, set, dictまでもが偽とみなされる。

以下のRubyの例ではどちらのifの中も実行されるが、

# ruby
if 0
  print('実行される')
end
if []
  print('実行される')
end
以下のPythonの例ではどちらのifの中も実行されない。
# python
if 0:
  print('実行されない')

if []:
  print('実行されない')

さて、まだ触りも触りだけど、言語としてはオブジェクトや属性や関数のあり方とか、JavasScriptに近い臭いがする。コードにコメントの形でドキュメントを埋め込む標準形を持っている言語は少なくないけれど、コメントではない__doc__属性を標準で持っているというのは面白い。あと、2系では基本的に整数除算だった/演算子を、3系では実数除算にしてしまったという話はビックリしたのと同時に、2系に留まる人の気持ちが分かった。そんな根源的なところを変えるか?

2014年8月31日日曜日

Rubyistが歩んでみる蛇の道はPython その0

今まで何となく避けてきたPythonに、ちょいと向き合ってみようと思い立った。自分で積極的にPythonのコードを書くようになるかは分からないけど、他人が書いたコードを読みたいな、と。また、新しい言語に触れるってことは、その言語の思想に触れるってことでもあるから、それがまた別の機会で活きるかもしれないし。

さて、ここで問題となるのがバージョン。Pythonは2系と3系で結構変化していて、長らく移行に手間取っているらしい。Rubyに例えると2系へのジャンプみたいなもんかな。これから学ぼうとしている自分にはレガシーな資産も呪縛も無いので、せっかくだから、俺はこの3系を選ぶぜ。早速Homebrewのpython3というformulaを使ったら

% python3 --version
Python 3.4.1
というバージョンのものがインストールされた。

とりあえず教科書はDive Into Python 3にしてみようかと思い、PDF版をiPad AirとiPod touchに放り込んだ。日本語版もあったけど、こちらはPDF版が見当たらない。

2014年7月1日火曜日

RubyのEnumerator#with_index

Rubyらしくイテレータを使ってループを記述したいけど、インデックスも併用したい。ただ、eachじゃないからeach_with_indexは使えない。そんなときはEnumerator#with_indexを使う。

irb> %w(foo bar baz).map.with_index {|e, i| "#{i} : #{e}"}
=> ["0 : foo", "1 : bar", "2 : baz"]
irb> %w(foo bar baz).map.with_index(1) {|e, i| "#{i} : #{e}"}
=> ["1 : foo", "2 : bar", "3 : baz"]
こんな感じで、任意のEnumeratorからインデックス付きEnumeratorを作れる。with_indexの引数でインデックスの初期値を指定できるのも、地味に嬉しい。

2014年6月5日木曜日

Rubyで負の数の16進表現

Rubyで数値を16進文字列に変換するには

irb> 255.to_s(16)
=> "ff"
とto_sを使えばいい。が、負の値に対して同じことをやると
irb> -255.to_s(16)
=> "-ff"
こんな残念な結果を見ることになる。いつも思うんだけど、これって誰が望んでるんだ?

で、負の数のビットパターンを直接見たい場合は

irb> (-255 & 0xffff).to_s(16)
=> "ff01"
irb> (-255 & 0xffffffffffffffff).to_s(16)
=> "ffffffffffffff01"
こうすればいいと気が付いた。16進リテラルは必ず非負扱いのようなので、符号ビットは常にゼロ。当然、どんなに符号拡張されても符号ビットは常にゼロ。それと論理積を取ればどんな値でも符号ビットが落ちるので、それからto_sすれば望んだ結果になる。

2014年6月4日水曜日

RubyのFixnumとBignumの境界

RubyのFixnumは符号付き31ビットだと思っていたら、いつの間にか符号付き63ビットになっていた。厳密には環境依存らしいけど、今どきの64ビット環境なら大体は

irb> 0.size
=> 8
irb> (2**62-1).class
=> Fixnum
irb> (-2**62).class
=> Fixnum
なんだろう。家のMacはそうだった。

符号付き31ビットって±10億程度、100均の電卓に毛が生えた程度の精度しかないので、結構簡単にBignumになるのは嫌だなぁ、と思っていたのだけれど、63ビットあれば大抵のことはFixnumで片付くね。

2014年2月26日水曜日

RubyのKconv::AUTOと互換性

今更ながら、RubyのKconv::AUTOが0からnilになっていたことに気が付いた。1.9系で変更されていたみたい。Kconv::AUTOとnilが別物のつもりで書いていたコードを直さなければ。

1.9以降は標準で多言語対応しているとは言っても、文字コードの自動判別で結局Kconv(NKF)を使うんだよなぁ。