2進、8進、10進、16進の各表現を相互に変換する
リテラル
8進数、16進数を数値リテラルとして書くには、 0x 0X 0o 0O の表記を使います。
code: (haskell)
Prelude> 255 :: Int
255
Prelude> 0xFF :: Int -- 16進数表記
255
Prelude> 0o377 :: Int -- 8進数表記
255
また、 BinaryLiterals 拡張を有効にすると、0b 0B により2進数表記を用いるこ
とができます。
code: (haskell)
Prelude> :set -XBinaryLiterals
Prelude> 0b11111111
255
文字列表記
base パッケージに同梱される Numeric モジュールに数値型を文字列型に変換する関数があります。 ShowS 型を返すため、初期文字列 "" を入力する必要があることに注意してください。
code: (haskell)
ghci> import Numeric
ghci> show 123
"123"
ghci> showHex 123 "" -- 16進数表記
"7b"
ghci> showOct 123 "" -- 8進数表記
"173"
2進数表記用の関数は用意されていませんが、同じパッケージ内にある showIntAtBase 関数を利用できます。ただし、この関数を利用するには数字1桁を1文字に変換する関数が必要です。 Data.Char から intToDigit 関数を借りてきます。
code: (haskell)
ghci> import Numeric
ghci> import Data.Char
ghci> showIntAtBase 2 intToDigit 123 "" -- 123を2進数表記
"1111011"
文字列表記の読み込み
同じく Numeric モジュールの、 readHex 、 readOct が使えます。ただし、これ
らの式は ReadS a 型であるため、数値文字列を渡した後に fst . head で先頭を取り出す必要があります。
code: (haskell)
ghci> import Numeric
ghci> fst $ head $ readHex "FF"
255
ghci> fst $ head $ readOct "377"
255
ただし、パースできない場合にこの記述を使うと、例外を吐いたり先頭部分だけがパースされたりしてしまいます。パースできるかわからない場合はパターンマッチすべきです。
code: (haskell)
ghci> case readHex "EFG" of (x, []):_ -> Right x; otherwise -> Left "can't parse"
Left "can't parse"
ghci> case readHex "EF" of (x, []):_ -> Right x; otherwise -> Left "can't parse"
Right 239
2進数は readInt が使えます。1文字を1桁に変換する digitToInt を Data.Char から import します。また、各桁がパース対象文字かを判断するための式 (elem "01") を渡します。
code: (haskell)
ghci> import Numeric
ghci> import Data.Char
ghci> fst $ head $ readInt 2 (elem "01") digitToInt "11111111"
255
変換
ここまでの書式を利用すると、2進、8進、10進、16進の相互変換ができます。
code: (haskell)
import Numeric (showHex, readInt)
import Data.Char (digitToInt)
-- 10進→16進
decToHex :: String -> String
decToHex dec = showHex (read dec) ""
-- 2進→10進
binToDec :: String -> String
binToDec bin = show intval
where
intval = fst $ head $ readInt 2 (elem "01") digitToInt bin
code: (haskell)
decToHex "255"
"ff"
binToDec "11111111"
"255"