首页 > 解决方案 > 如何使用 map 将自定义 Word8 应用于 Char 函数将 ByteString 转换为 Text?

问题描述

我正在尝试学习 Haskell,我想我会尝试复制 Linux 'xxd' 实用程序。但是我被困在右侧列(显示 ASCII 或非打印字符的空白)。

提醒一下,典型的 xxd 输出如下所示:

00000000: 4927 6d20 7472 7969 6e67 2074 6f20 6c65  I'm trying to le
00000010: 6172 6e20 4861 736b 656c 6c2e 2041 7320  arn Haskell. As 
...

我还想利用 Unicode“控制图片”块来显示控制代码 0..31 的小符号,而不是点或占位符。所以我有一个辅助函数,可以将 Word8 转换为 Char,同时用控制图片块中的等效字符替换控制字符。

http://www.unicode-symbol.com/block/Control_Pictures.html

约束:最终程序将从磁盘读取文件,因此我希望读取 ByteString 或惰性 ByteString。另外我想使用 Data.Text 来保存输出而不是字符串。

理想情况下:我想避免将 ByteString 转换为其他批发的东西,例如 [Word8],因为 - 最终 - 我需要学习如何使用它,而不是围绕它工作。

我的问题是我不能map为我工作。B.map 和 T.map 都不起作用,因为它们需要一个 function ([a] -> [a])Prelude.map看起来更有希望,([a] -> [b])但我无法让它与导入的类型一起使用。所以我尝试定义自己的map(只是尝试找到可以工作的东西,然后当我有更好的理解时,我可以用内置函数替换)但这也不起作用。

我拥有的非功能代码如下

import qualified Data.ByteString as B
import qualified Data.Text as T
import Data.Word
import Data.Char

{- Make some normally undisplayable bytes into displayable chars -}
displayableChar :: Word8 -> Char
displayableChar w
  | i < 32  = chr (0x2400 + i)  -- 0x2420 control codes
  | i < 33  = chr 0x2423        -- 0x2423 trough for space
  | i < 127 = chr i
  | i < 128 = chr 0x2421        -- 0x2421 del
  | otherwise = ' '
  where i = fromIntegral w


mymap :: (Word8 -> Char) -> B.ByteString -> [Char]
mymap f bstr
  | bstr == B.empty = []
  | otherwise       = f x : map f xs
  where
    x = B.head bstr
    xs = B.tail bstr


test_data = B.pack [1..250]

欢迎提出建议和建议,请就应用displayableChar到 ByeString 中的每个字节并获取文本的“正确”方式是什么。

标签: haskell

解决方案


你写map而不是mymap在你的函数定义中:

mymap :: (Word8 -> Char) -> B.ByteString -> [Char]
mymap f bstr
  | bstr == B.empty = []
  | otherwise       = f x : mymap f xs   -- <- here
  where
    x = B.head bstr
    xs = B.tail bstr

另一种方法是用于B.unwrap获取列表,Word8以便您可以应用map哪些适用于列表:

mymap :: (Word8 -> Char) -> ByteString -> [Char]
mymap f bs = map f (B.unwrap bs)

推荐阅读