【问题标题】:Manipulating hexadecimal data in Haskell在 Haskell 中处理十六进制数据
【发布时间】:2014-11-13 07:51:41
【问题描述】:

我有一个 CSV 文件,其中包含我想在 Haskell 中处理的记录数据。 CSV 文件中的数据为十六进制格式。当我将它读入 Haskell 时,我有诸如“0xFF5FFFC8EC5FFEDF”之类的字符串,它代表 8 个字节的数据。

为了处理数据,我想将字符串转换为允许我进行位旋转(按位与、或和异或)的数据类型。然后当我完成后,我想将最终结果转换回十六进制字符串,以便将其写入文件。

这在 Haskell 中容易做到吗?我应该查看哪些模块?

【问题讨论】:

  • 你的十六进制字符串有多长?它们总是适合 64 位 int,还是可以更长?

标签: haskell bit-manipulation


【解决方案1】:

您可以使用read 来解析整数或浮点数。 它位于 Prelude 中,因此您无需任何其他模块即可使用它。

试试:

a = "0xFF5FFFC8EC5FFEDF"
b = read a::Double

(它给出 b = 1.8401707840883393e19)

另外,为了解析 CSV,您也可以创建自己的函数来执行此操作。 一周前我刚刚写了一个简单的 CSV 解析器。

module CSVUtils
    ( parseCSV, showCSV
    , readCSV , writeCSV
    , colFields
    , Separator, Document
    , CSV      , Entry
    , Field
    )
where

import Data.Char
import Data.List
{-
A simple utility for working with CSV (comma-separated value) files. These
are simple textual files where fields are delimited with a character (usually a comma
or a semicolon). It is required that the CSV document is well-formed, i.e., that 
it contains an equal number of fields per row.
-}
type Separator = String
type Document = String
type CSV = [Entry]
type Entry = [Field]
type Field = String

doc = "John;Doe;15\nTom;Sawyer;12\nAnnie;Blake;20"
brokenDoc = "One;Two\nThree;Four;Five"
{-
(a) Takes a separator and a string representing a CSV document and returns a 
CSV representation of the document. 
-}
-- !! In the homework text is said Separator is going to be Char and now the type is String
-- !! so I'm just going to take head
parseCSV :: Separator -> Document -> CSV
parseCSV sep doc 
    | (head sep) `notElem` doc                     = error $ "The character '"++sep++"' does not occur in the text"
    | 1 /= length ( nub ( map length (lines doc))) = error $ "The CSV file is not well-formed"               
    | otherwise                                    = [splitOn sep wrd | wrd <- lines doc ]
{-
(b) Takes a separator and a CSV representation of
a document and creates a CSV string from it.
-}
showCSV :: Separator -> CSV -> Document
showCSV sep = init . unlines . map (intercalate sep)
{-
(c) Takes a CSV document and a field number
and returns a list of fields in that column.
-}
colFields :: Int -> CSV -> [Field]
colFields n csv = [ if length field > n 
                    then field !! n 
                    else error $ "There is no column "++(show n)++" in the CSV document" 

                    | field <- csv]
{-
(d) Takes a file path and a separator and returns the CSV representation of the file.
-}
readCSV :: Separator -> FilePath -> IO CSV
readCSV sep path = do
    file <- readFile path
    return $ parseCSV sep file

{-
(e) Takes a separator, a file path, and a CSV document and writes the document into a file.
The return type of writeCSV is a special case of IO { we need to wrap an impure
action, but do not actually have to return anything when writing. Thus, we
introduce (), or the unit type, which holds no information (consider it a 0-
tuple).
-}
writeCSV :: Separator -> FilePath -> CSV -> IO ()
writeCSV sep path csv = writeFile path (showCSV sep csv)

【讨论】:

  • ;) 是的,阅读非常酷。只是不要忘记使用 :: 指定类型
【解决方案2】:

我将假设您的二进制数据可以是任意长度。例如,如果您的二进制数据适合 Int64,则可以简化事情。

我会推荐以下库和模块:

有关如何对 ByteStrings 执行按位运算的示例,请查看 Haskell 学院本教程的结尾:

https://www.fpcomplete.com/school/to-infinity-and-beyond/pick-of-the-week/bytestring-bits-and-pieces

cassava的使用示例,请查看源repo的examples目录:

https://github.com/tibbe/cassava/tree/master/examples

【讨论】:

    猜你喜欢
    • 2014-09-14
    • 2020-05-10
    • 2011-07-07
    • 2011-04-26
    • 1970-01-01
    • 2014-02-18
    • 2020-02-04
    • 2012-06-16
    • 1970-01-01
    相关资源
    最近更新 更多