将字符串转换为字节字符串的最佳方法是什么?

43

在Haskell中将字符串转换为ByteString的最佳方法是什么?

对于这个问题,我的第一反应是

import qualified Data.ByteString as B
import Data.Char (ord)

packStr = B.pack . map (fromIntegral . ord)

但是这似乎并不令人满意。


6
现代:通常应该将 [Char] 转换为 Text,将 [Word8] 转换为 ByteString。不过仍然要使用 pack :) - alternative
4
将Unicode转换为字节需要使用Unicode编码。使用pack更类似于一种不安全的类型转换。 - tibbe
3个回答

61

这是我用于Haskell字符串/文本/字节串严格/惰性转换的备忘单,假设所需编码为UTF-8。Data.Text.Encoding库有其他可用的编码。

请务必不要使用OverloadedStrings写:

lazyByteString :: BL.ByteString
lazyByteString = "lazyByteString ä ß" -- BAD!

这将以意想不到的方式进行编码。请尝试

lazyByteString = BLU.fromString "lazyByteString ä ß" -- good

相反。

'Text' 类型的字符串字面量在编码方面表现良好。

速查表:

import Data.ByteString.Lazy as BL
import Data.ByteString as BS
import Data.Text as TS
import Data.Text.Lazy as TL
import Data.ByteString.Lazy.UTF8 as BLU -- from utf8-string
import Data.ByteString.UTF8 as BSU      -- from utf8-string
import Data.Text.Encoding as TSE
import Data.Text.Lazy.Encoding as TLE

-- String <-> ByteString

BLU.toString   :: BL.ByteString -> String
BLU.fromString :: String -> BL.ByteString
BSU.toString   :: BS.ByteString -> String
BSU.fromString :: String -> BS.ByteString

-- String <-> Text

TL.unpack :: TL.Text -> String
TL.pack   :: String -> TL.Text
TS.unpack :: TS.Text -> String
TS.pack   :: String -> TS.Text

-- ByteString <-> Text

TLE.encodeUtf8 :: TL.Text -> BL.ByteString
TLE.decodeUtf8 :: BL.ByteString -> TL.Text
TSE.encodeUtf8 :: TS.Text -> BS.ByteString
TSE.decodeUtf8 :: BS.ByteString -> TS.Text

-- Lazy <-> Strict

BL.fromStrict :: BS.ByteString -> BL.ByteString
BL.toStrict   :: BL.ByteString -> BS.ByteString
TL.fromStrict :: TS.Text -> TL.Text
TL.toStrict   :: TL.Text -> TS.Text
请给 Peaker 的答案点赞(+1),因为他正确地处理了编码。

10
我花了一点时间才弄清楚 Data.ByteString.UTF8utf8-string 包中。 - Matthias Braun
我还需要在我的 Package.yaml 文件中添加 - utf8-string - bg2000 Reinstate Monica
这张备忘单对像我这样的新手来说真是救命稻草!谢谢! - TimeTravelPenguin
你有任何想法为什么我的编译器会显示“找不到模块'Data.ByteString.Lazy.UTF8'”? - plasma

32

Data.ByteString.UTF8.fromString也是很有用的。使用Char8版本会失去unicode特性,而UTF8将生成UTF8编码的ByteString。你必须选择其中一个。


如果有人问起:这个函数在Hoogle中没有被找到,因为它只索引了一小部分库(那些随GHC一起发布的库)。扩展Hoogle所索引的库集合已经被提出过多次,但由于Hoogle开发者(Neil)时间限制的原因,尚未实现。顺便提一下,这里讨论的函数来自utf8-string包。 - Thomas M. DuBuisson
@TomMD:Hayoo 解决了这个问题:http://holumbus.fh-wedel.de/hayoo/hayoo.html#0:String%20-%3E%20ByteString - Peaker
@peaker:不太满意。Hayoo在类型搜索方面做得很差,特别是当类型是通用的或多态的时候。 - Thomas M. DuBuisson

15

安全的方法将涉及对Unicode字符串进行编码:

import qualified Data.ByteString as B
import qualified Data.Text as T
import Data.Text.Encoding (encodeUtf8)

packStr'' :: String -> B.ByteString
packStr'' = encodeUtf8 . T.pack

关于其他回答:Data.ByteString.Char8.pack 与问题中的版本实际上是相同的,不太可能是您想要的内容。
import qualified Data.ByteString as B
import qualified Data.ByteString.Char8 as C
import qualified Data.Text as T
import Data.Text.Encoding (encodeUtf8)
import Data.Char (ord)

packStr, packStr', packStr'' :: String -> B.ByteString
packStr   = B.pack . map (fromIntegral . ord)
packStr'  = C.pack
packStr'' = encodeUtf8 . T.pack

*Main> packStr "hellö♥"
"hell\246e"
*Main> packStr' "hellö♥"
"hell\246e"
*Main> packStr'' "hellö♥"
"hell\195\182\226\153\165"

Data.ByteString.UTF8.fromString很好用,但需要使用utf8-string包,而Data.Text.Encoding则默认集成在Haskell平台中。


2
Codec.Binary.UTF8.String 也可以使用。 - Jeremy List

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接