0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

Rubyでゼロパディングの数値文字列を扱うときのメモ

Posted at

なにがあったか

8桁のゼロパディングされた10進数の数字文字列について、値が本当に数値かどうかをチェックしたかった。数値かどうかの判定はInteger()に文字列を投げて例外がでるかどうかでチェックする方法があるようなので、やってみた。

$ ruby -v
ruby 2.3.1p112 (2016-04-26 revision 54768) [x86_64-darwin15]
def integer_string?(str)
  Integer(str)
  true
rescue ArgumentError
  false
end

integer_string?("00004820") #=> false

true になることを期待していたが、数値ではないと判定されてしまった。

なぜそうなった?

"00004820" は8進数として認識されていたからだった。
調べていくとなるほど当然の挙動であったが、普段あまり10進数以外を扱わないので、最初は面食らってしまった。

Integer("00000010") #=> 8
Integer("00000008") #=> ArgumentError、8進数で表現できない

Ruby実装を追っていくと、どうもこの辺で文字列から基数を判断している様子?
https://github.com/ruby/ruby/blob/ruby_2_3/bignum.c#L4013
実装全部をおいかけたわけではないが、次のような理解をした。

# 文字列の先頭が0の場合は接頭辞として扱われ、2文字目で基数が決定される
Integer("0x10") #=> 16 (16進数)
Integer("0b10") #=> 2 (2進数)
Integer("0o10") #=> 8 (8進数)
Integer("0d10") #=> 10 (10進数)

# 先頭が0で特定の接頭辞がとして判断できなければ、8進数として扱う
Integer("010") #=> 8 (8進数)

# 文字列の先頭が0じゃなければ10進数として扱う
Integer("123") #=> 123 (10進数)

こうすればいい

ちゃんと基数を設定してあげると良さそう。
でも代わりに接頭辞表現を受け付けなくなったりするので、使い所によるかも。

def decimal_integer_string?(str)
  Integer(str, 10)
  true
rescue ArgumentError
  false
end

decimal_integer_string?("00004820") #=> true
decimal_integer_string?("0000482a") #=> false *不要な文字が混じっている
decimal_integer_string?("0x01") #=> false *この表記は受け付けなくなるので注意
integer_string?("0x01") #=> true *基数を指定しなければtrue扱い

感想: 難しいし奥深いなぁ(小並感)

参考

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?