2015-06-28 6 views
1

Когда я запускаю этот код, я получаю ошибку декодирования от Data.Text. Что я делаю не так?Преобразование ByteString, созданное System.Entropy to Text

import Data.Text     (Text, pack, unpack) 
import Data.Text.Encoding   (decodeUtf8) 
import Data.ByteString    (ByteString) 
import System.Entropy 

randBS :: IO ByteString 
randBS = do 
    randBytes <- getEntropy 2048 
    return randBytes 

main :: IO() 
main = do 
    r <- randBS 
    putStrLn $ unpack $ decodeUtf8 r 

Ошибка:

Cannot decode byte '\xc4': Data.Text.Internal.Encoding.Fusion.streamUtf8: 
Invalid UTF-8 stream 

Я хотел бы генерировать случайные байты, которые будут использоваться в качестве маркера AUTH.

Я на Mac OS X (Yosemite) и GHC Версия 7.10.1

ответ

4

randBS возвращает случайных байтовне UTF-8 закодированные данные! То, что у вас есть, - это не представление Text, поэтому не имеет значения, какая функция вы используете. будет столкнуться с некоторой ошибкой декодирования, поэтому вам нужно будет использовать что-то вроде decodeUtf8With и использовать обработчик ошибок для замены недействительных байтов с помощью их буквальный экземпляр.

Что-то вроде:

import Data.Text     (Text, pack, unpack) 
import Data.Text.Encoding   (decodeUtf8With) 
import Data.ByteString    (ByteString) 
import Data.Char     (chr) 
import Control.Applicative   ((<$>)) 
import System.Entropy 

handler _ x = chr <$> fromIntegral <$> x 

randBS :: IO ByteString 
randBS = do 
    randBytes <- getEntropy 2048 
    return randBytes 

main :: IO() 
main = do 
    r <- randBS 
    putStrLn $ unpack $ decodeUtf8With handler r 

Не тестировался, в этот момент я не установлен GHC: s


Возможно, даже лучше будет просто использовать шестнадцатеричную кодировку вместо UTF -8 + обработчик ошибок. Вы можете сделать это с помощью библиотеки base16-bytestring. Таким образом, вы бы сначала использовать encode :: ByteString -> ByteString, чтобы получить представление только значений ASCII:

import Data.Text     (Text, pack, unpack) 
import Data.ByteString    (ByteString) 
import Data.ByteString.Encoding  (decodeUtf8) 
import Data.ByteString.Base16  (encode) 
import System.Entropy 

--- ... randBS as before 

main = do 
    r <- randBS 
    putStrLn $ unpack $ decodeUtf8 $ encode r 
+1

Я предложил бы использовать что-то вроде [base16-байтовой строки] (https://hackage.haskell.org/package/base16- байтовой строки). Выход будет длиннее, но всегда будет иметь одинаковую длину (в два раза больше, чем входной ByteString), а выход будет шестнадцатеричным вместо тарабарщины (что больше подходит для токена аутентификации). – cchalmers

+0

@cchalmers Вы правы. Это действительно зависит от выхода, которого хочет OP, чего он действительно не объяснил. – Bakuriu

+0

@Bakuriu спасибо! Я хотел бы создать токен сеанса, который является безопасным. Этот токен будет храниться в БД и совместно с клиентом. Кодирование, вероятно, даст мне то, что я хочу. – Ecognium