Ber*_*ian 0 encoding haskell bytestring
您好,我对编码数据所需的所有Haskell模块感到有点困惑,String以便ByteString进行高效写入.
我不明白你如何将a转换Data.ByteString.Lazy为a Data.ByteString.Char8,反之亦然.
我需要知道什么?因为我不能让用途的所有这些可能的组合......
Data.ByteString,Data.ByteString.Lazy,Data.ByteString.Char8,然后还有Data.Text.....我需要以轻松,高效地将字符串写入到文件和副-versa什么?(使用适当的编码)
PS目前阅读真实世界Haskell,我对所有这些模块感到非常困惑.
这是路线图的一个镜头.
您可能知道,Haskell String类型只是一个类型的同义词[Char],其中Char的数据类型可以表示单个Unicode代码点.这使得String完美的数据类型代表文本数据,除了小问题 - 作为盒装Char值的链接列表- 它可能非常低效.
包中的Text数据类型text解决了这个问题. Text也就像是String一个Char值列表的表示,但它不使用实际的Haskell列表,而是使用时间和空间有效的表示.String无论何时需要有效地处理文本(Unicode)数据,它都应该是您的首选替代品.
与标准Haskell库中的许多其他数据类型一样,它有懒惰和严格的变体.两种变体都具有相同的名称Text,但它们包含在单独的模块中,因此您可以执行以下操作:
import qualified Data.Text as TS
import qualified Data.Text.Lazy as TL
Run Code Online (Sandbox Code Playgroud)
如果你需要在同一个程序中使用这两个TS.Text和TL.Text变体.
变体之间的确切差异在Data.Text的文档中描述.简而言之,您应该默认使用严格版本.您只在两种情况下使用惰性版本.首先,如果您计划Text一次处理一个大的值,将其视为文本"流"而不是"字符串",则懒惰版本是一个不错的选择.(例如,读取大量CSV数字文件的程序可能会将该文件读取为长延迟Text流,并将结果存储为有效的数字类型Vector,如未装箱的Double值,以避免将整个输入文本保留在内存中.)其次,如果你是Text从很多小块中构建一个大字符串,那么你不想使用严格的版本,因为它们的不变性意味着它们需要在你添加东西时被复制.相反,你想要使用带有函数的惰性变体Data.Text.Lazy.Builder.
另一方面,ByteString来自bytestring包的数据类型是字节列表的有效表示.就像Text是一个高效版本一样[Char],您应该将其ByteString视为一个有效的版本[Word8],Word8Haskell类型在哪里表示一个值为0-255的单个无符号数据字节.同样地,您可以将a ByteString视为表示要从文件读取或写入文件的一块内存或一大块数据,精确地按字节为单位.它还有懒惰和严格的口味:
import qualified Data.ByteString as BS
import qualified Data.ByteString.Lazy as BL
Run Code Online (Sandbox Code Playgroud)
并且使用变体的注意事项类似于Text.
在Haskell程序中,通常将Unicode字符串内部表示为String或者Text值.但是,要从文件中读取它们或将它们写入文件,需要将它们编码到字节序列中并从中进行解码.
处理此问题的最简单方法是使用Haskell函数自动处理编码和解码.您可能已经意识到,Prelude直接读取和写入字符串已经有两个函数:
readFile :: FilePath -> IO String
writeFile :: FilePath -> String -> IO ()
Run Code Online (Sandbox Code Playgroud)
此外,还有readFile和writeFile函数text是做到这一点.你可以在两个版本Data.Text.IO和Data.Text.Lazy.IO.它们看起来具有相同的签名,但是一个是在严格Text类型上运行而另一个是在惰性Text类型上运行:
readFile :: FilePath -> IO Text
writeFile :: FilePath -> Text -> IO ()
Run Code Online (Sandbox Code Playgroud)
您可以告诉这些函数自动进行编码和解码,因为它们返回并接受Text值,而不是ByteString值.使用的默认编码取决于操作系统及其配置.在典型的现代Linux发行版中,它将是UTF-8.
或者,您可以使用bytestring包中的函数从文件中读取或写入原始字节(同样,根据模块,可以是惰性版本或严格版本):
readFile :: FilePath -> IO ByteString
writeFile :: FilePath -> ByteString -> IO ()
Run Code Online (Sandbox Code Playgroud)
它们与text版本具有相同的名称,但您可以看到它们处理原始字节,因为它们返回并接受ByteString参数.在这种情况下,如果要将这些ByteStrings用作文本数据,则需要自己对其进行解码或编码.例如,如果ByteString代表文本的UTF-8编码版本,则从Data.Text.Encoding(对于严格版本)或Data.Text.Lazy.Encoding(对于懒惰版本)这些函数是您正在寻找的:
decodeUtf8 :: ByteString -> Text
encodeUtf8 :: Text -> ByteString
Run Code Online (Sandbox Code Playgroud)
现在,模块中的Data.ByteString.Char8和Data.ByteString.Lazy.Char8是一个特例.当使用几种"ASCII保留"编码方案(包括ASCII本身,Latin-1和其他Latin-x编码以及UTF-8)中的一种编码纯ASCII文本时,结果证明编码ByteString只是一个简单的编码Unicode代码的每字符字节编码点0到127.稍微更普遍的是,当文本用Latin-1编码时,编码ByteString只是一个简单的单字节每字符编码的Unicode代码点0到255.在这些情况下,仅在这些情况下,这些模块中的函数可以安全地用于绕过显式编码和解码步骤,并直接通过自动转换单个字节将字节字符串视为ASCII和/或Latin-1文本unicode Char值和返回.
因为这些函数仅适用于特殊情况,所以除了专门的应用程序之外,通常应该避免使用它们.
另外,正如评论中提到的,ByteString这些Char8模块中的变体与普通严格和惰性ByteString变体没有任何不同; 只是将它们视为Char值的字符串而不是那些模块中Word8的函数的值- 数据类型是相同的,只是函数接口是不同的.
因此,如果您使用纯文本和操作系统的默认编码,只需使用来自的严格Text数据类型Data.Text和(高效)IO函数Data.Text.IO.您可以使用惰性变体进行流处理或从小块中构建大字符串,您可以使用Data.Text.Read一些简单的解析.
String在大多数情况下,您应该能够避免使用,但如果您发现需要来回转换,那么Data.Text(或Data.Text.Lazy)中的这些转换函数将非常有用:
pack :: String -> Text
unpack :: Text -> String
Run Code Online (Sandbox Code Playgroud)
如果您需要更多地控制编码,您仍然希望在Text整个程序中使用,除了在您正在读取或写入文件的"边缘".在这些边缘,使用来自Data.ByteString(或Data.ByteString.Lazy)的I/O函数,以及来自Data.Text.Encoding或的编码/解码函数Data.Text.Lazy.Encoding.
如果您发现需要混合严格和惰性变体,请注意Data.Text.Lazy包含:
toStrict :: TL.Text -> TS.Text -- convert lazy to strict
fromStrict :: TS.Text -> TL.Text -- vice versa
Run Code Online (Sandbox Code Playgroud)
并Data.ByteString.Lazy包含ByteString值的相应函数:
toStrict :: BL.ByteString -> BS.ByteString
fromStrict :: BS.ByteString -> BL.ByteString
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
196 次 |
| 最近记录: |