2012-01-16 14 views
8

Siempre encuentro con el siguiente error al intentar leer un ByteString:
Prelude.read: no parse¿Cuál es la mejor forma de convertir ByteString en Int?

He aquí una muestra de código que hará que este error se produzca antes de mostrarlo en un navegador:

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]] 

O tal más simplemente:

simple bs = read (show bs) :: Int 

Por alguna razón, después de show bs la cadena resultante incluye citas. Para evitar el error, tengo que eliminar las comillas, entonces read. utilizo la siguiente función de copiado de internet para hacerlo:

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 

Entonces simple bs = read (sq.show bs) :: Int funciona como se espera.

  1. ¿Por qué es este el caso?
  2. ¿Cuál es la mejor manera de convertir una ByteString en una Int?

Respuesta

9

Show se utiliza para crear una representación String de algo, que es útil para la depuración y serialización de texto sin formato. La clase de tipo Show no es solo una forma elegante de convertir nada en un String. Es por eso que ByteString agrega comillas a la cadena: porque es posiblemente más fácil de leer de esa manera al depurar o deserializar una secuencia de datos.

Usted puede utilizar la función Data.ByteString.Char8.unpack para convertir un ByteString a un String, pero tenga en cuenta que este descomprime el byte byte-por-ByteString, que meta la pata caracteres Unicode de alto valor u otros caracteres que se almacenan como más de un byte ; Si desea hacer algo distinto de usar read en el resultado, le recomiendo convertir el ByteString en Text, lo que ofrece más flexibilidad en esta situación. Suponiendo que su codificación es UTF8 en este caso (como debería ser el valor predeterminado en Snap), puede usar la función Data.Text.Encoding.decodeUtf8 para esto. Para convertir un valor de Text a String con símbolos Unicode correctos, utilice Data.Text.unpack.

Una vez que tenga un String, es libre de read tanto como desee; alternativamente, puede elegir leer un valor Text directamente usando las funciones en el módulo Data.Text.Read.

+0

Para mí, la pregunta n. ° 2 aún no está clara, o puede tratarse de un caso de uso más específico del que tengo curiosidad y creo que está relacionado con esta pregunta inicial: ¿Qué pasa si hay algún tipo de " campo de longitud "que se analiza como ByteString de longitud 4, que de hecho describe un Int32. ¿Su solución alternativa propuesta sigue siendo válida? Como una solución más cómoda, estaba buscando una biblioteca que pueda tomar un tipo de ByteString y devolverá la Int. Correcta. ¿Hay alguna biblioteca que pueda manejar este caso de uso? –

10

Cuál es la mejor manera de convertir un ByteString a un X depende de X. Si tiene una buena conversión de String, ir a través de Data.BytString.Char8.unpack puede ser bueno, si es un ASCII ByteString. Para codificación UTF-8 ByteString s, el paquete utf8-string contiene la función de conversión toString. Para algunos tipos específicos, como Int, como se menciona en el título, existen conversiones especiales más rápidas. Por ejemplo, Data.ByteString.Char8.readInt y readInteger.

+1

Para quienes vienen de internet: ** ¡Esta es la respuesta si la "mejor manera" también significa "manera eficiente" para usted! ** – donatello

Cuestiones relacionadas