2012-01-16 5 views
8

я всегда работать в следующую ошибку при попытке чтения байтовой строки:
Prelude.read: no parseКаков наилучший способ преобразования ByteString в Int?

Вот пример кода, который будет привести к возникновению этой ошибки при оказании в браузере:

factSplice :: SnapletSplice App App 
factSplice = do 
    mbstr <- getParam "input" -- returns user input as bytestring 
    let str = maybe (error "splice") show mbstr 
    let n = read str :: Int 
    return [X.TextNode $ T.pack $ show $ product [1..n]] 

Или, возможно, более просто:

simple bs = read (show bs) :: Int 

По какой-то причине, после show bs результирующая строка включает в кавычки. Итак, чтобы обойти ошибку, я должен удалить цитаты, а затем read. я использую следующую функцию, скопированную из Интернета, чтобы сделать так:

sq :: String -> String 
sq [email protected][c]      = s 
sq ('"':s) | last s == '"' = init s 
      | otherwise  = s 
sq ('\'':s) | last s == '\'' = init s 
      | otherwise  = s 
sq s       = s 

Тогда simple bs = read (sq.show bs) :: Int работает, как ожидалось.

  1. Почему это так?
  2. Каков наилучший способ преобразования ByteString в Int?

ответ

9

Show используются для создания String представления чего-то, что полезно для отладки и простого текста сериализации. Класс Show не просто причудливый способ преобразования чего-либо в String. Вот почему ByteString добавляет кавычки в строку: потому что, возможно, легче читать ее таким образом при отладке или десериализации потока данных.

Вы можете использовать функцию Data.ByteString.Char8.unpack для преобразования ByteString в String, но учтите, что это распаковывает байт байт-в-ByteString, который путает с высокой добавленной стоимостью символы Unicode или другие символы, которые хранятся в более чем один байт ; если вы хотите сделать что-то другое, кроме использования read, я бы рекомендовал вместо этого преобразовать ByteString в Text, что обеспечивает большую гибкость в этой ситуации. Предполагая, что ваша кодировка UTF8 в этом случае (как должно быть по умолчанию в Snap), для этого вы можете использовать функцию Data.Text.Encoding.decodeUtf8. Чтобы затем преобразовать значение Text в String с правильными символами Юникода, вы используете Data.Text.unpack.

После того, как у вас есть String, вы можете бесплатно получить read столько, сколько хотите; в качестве альтернативы вы можете выбрать значение Text напрямую с помощью функций в модуле Data.Text.Read.

+0

На вопрос №2 все еще не так ясно - или это может быть просто более конкретный случай использования. Мне любопытно, и я думаю, что это связано с этим начальным вопросом: Что делать, если есть какой- lenght field ", которое анализируется как ByteString длины 4, что на самом деле описывает Int32. Является ли ваше предлагаемое решение обходным? В качестве более удобного решения я искал библиотеку, которая может принимать такой тип ByteString и вернет правильный Int. Есть ли библиотека, которая может обрабатывать этот прецедент? –

10

Какой лучший способ конвертировать ByteString в X зависит от X. Если у вас хорошая конверсия от String, переход через Data.BytString.Char8.unpack может быть хорошим, если это ASCII ByteString. Для кодированного UTF-8 ByteString s пакет utf8-string содержит функцию преобразования toString. Для некоторых конкретных типов, таких как Int, как указано в названии, существуют специальные более быстрые преобразования. Например, Data.ByteString.Char8.readInt и readInteger.

+1

Для тех, кто приходит из Интернета: ** Это ответ, если «лучший способ» также означает «эффективный способ» для вас! ** – donatello

Смежные вопросы