2009-12-24 129 views
54

如何以二进制或十六进制打印haskell中的整数文字?如何在haskell中以二进制或十六进制打印整数文字?

printBinary 5 => "0101" 

printHex 5 => "05" 

哪些库/函数允许这样做?

我遇到了Numeric模块及其showIntAtBase函数,但一直无法正确使用它。

> :t showIntAtBase 

showIntAtBase :: (Integral a) => a -> (Int -> Char) -> a -> String -> String 

回答

69

数字模块包括几个functions for showing an Integral type在不同的基地,包括showIntAtBase。下面是使用的一些例子:

import Numeric (showHex, showIntAtBase) 
import Data.Char (intToDigit) 

putStrLn $ showHex 12 "" -- prints "c" 
putStrLn $ showIntAtBase 2 intToDigit 12 "" -- prints "1100" 
+6

对于像我这样没有向下滚动的懒惰的人来说,printf示例更加简洁灵活,并且可以执行其他有用的操作,例如,给出一个恒定长度的字符串和所有其他printf功能。而不是以上,只是: 'printf“%032b”5' – mozboz 2015-06-24 11:36:08

+11

@mozboz,Haskell中的'printf'更像是一个魔术,而不是一个用在严肃代码中的函数。格式字符串在运行时被解析(这可能会产生运行时错误),整个机制有点慢。 – dfeuer 2015-10-18 16:15:00

+0

这一个不适用于负数。 – CMCDragonkai 2017-04-04 13:04:42

3

可以转换整数,像下面为二进制:在GHCI

decToBin x = reverse $ decToBin' x 
    where 
    decToBin' 0 = [] 
    decToBin' y = let (a,b) = quotRem y 2 in [b] ++ decToBin' a 

用法:

Prelude> decToBin 10 
[1,0,1,0] 
+0

在最后一行的末尾有b:(decToBIn a)会不会更好? – prince 2015-12-05 15:27:13

+0

不应该0回馈0? 'decToBin'0 = [0]'也许? – Jaseem 2016-11-03 10:50:12

+0

@SjB,对负数不起作用 – 2016-11-14 15:41:56

26

如果导入NumericData.Char模块,你可以这样做:

showIntAtBase 2 intToDigit 10 "" => "1010" 
showIntAtBase 16 intToDigit 1023 "" => "3ff" 

这将为任何基地多达16个工作,因为这是所有intToDigit适用于。以上示例中额外的空字符串参数的原因是showIntAtBase返回类型为ShowS的函数,该函数将显示表示连接到现有字符串。

24

您也可以使用printf的包的printf到您的输出使用C风格的格式描述格式为:

import Text.Printf 

main = do 

    let i = 65535 :: Int 

    putStrLn $ printf "The value of %d in hex is: 0x%08x" i i 
    putStrLn $ printf "The html color code would be: #%06X" i 
    putStrLn $ printf "The value of %d in binary is: %b" i i 

输出:

的65535十六进制值是:0x0000ffff
的html颜色代码将是:#00FFFF
二进制中的值65535是:1111111111111111

+0

'printf“十六进制中的%d的值是:0x%08x”我是'是好的,因为printf可以是'IO()'和'字符串' – Nybble 2012-02-14 08:17:30

+0

是的的确的。我只是想弄明白,它可以用作返回String的纯函数。 – 2012-12-10 20:20:32

4

六角可以写与0x和二进制与0b前缀例如: -

> 0xff 
255 
>:set -XBinaryLiterals 
> 0b11 
3 

请注意二进制需要BinaryLiterals扩展。

2

你可以定义你自己喜欢的递归函数:

import Data.Char (digitToInt) 
import Data.Char (intToDigit) 

-- generic function from base to decimal 
toNum :: [Char] -> Int -> (Char -> Int) -> Int 
toNum [] base map = 0 
toNum s base map = base * toNum (init(s)) base map + map(last(s)) 

-- generic function from decimal to base k 
toKBaseNum :: Int -> Int -> (Int -> Char) -> [Char] 
toKBaseNum x base map | x < base = [map x] 
         | otherwise = toKBaseNum (x `div` base) base map ++ [map(x `mod` base)] 


-- mapping function for hex to decimal 
mapHexToDec :: Char -> Int 
mapHexToDec x | x == 'A' = 10 
       | x == 'B' = 11 
       | x == 'C' = 12 
       | x == 'D' = 13 
       | x == 'E' = 14 
       | x == 'F' = 15 
       | otherwise = digitToInt(x) :: Int 

-- map decimal to hex 
mapDecToHex :: Int -> Char 
mapDecToHex x | x < 10 = intToDigit(x) 
       | x == 10 = 'A' 
       | x == 11 = 'B' 
       | x == 12 = 'C' 
       | x == 13 = 'D' 
       | x == 14 = 'E' 
       | x == 15 = 'F' 

-- hex to decimal 
hexToDec :: String -> Int 
hexToDec [] = 0 
hexToDec s = toNum s 16 mapHexToDec 

-- binary to decimal 
binToDec :: String -> Int 
binToDec [] = 0 
binToDec s = toNum s 2 (\x -> if x == '0' then 0 else 1) 

-- decimal to binary 
decToBin :: Int -> String 
decToBin x = toKBaseNum x 2 (\x -> if x == 1 then '1' else '0') 

-- decimal to hex 
decToHex :: Int -> String 
decToHex x = toKBaseNum x 16 mapDecToHex 

说明: 正如你所看到的,toNum功能转换的k基于价值为十进制,使用给定的基础和映射函数。映射函数将特殊字符映射为十进制值(例如,A = 10,B = 11,...,十六进制)。对于二进制映射,您也可以使用像在binToDec中看到的lambda表达式。

toKBaseVal函数是相反的,将小数转换为基于k的值。我们再次需要一个映射函数,它相反:从十进制到基于k值的对应特殊字符。

作为一个测试,你可以输入:

binToDec(decToBin 7) = 7 

假设你想从十进制转换为八进制:

-- decimal to octal 
decToOct :: Int -> String 
decToOct x = toKBaseNum x 8 (\x -> intToDigit(x)) 

同样,我只使用一个lambda表达式,因为映射很简单:只需诠释数字。

希望有帮助!好的编程!